{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第11篇：时序数据处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第一部分：时间的基本概念\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "时间是一个比较特殊的事物，不像数字有具体的进制，可以做相关的计算。比如时间分秒时是60进制，时和天又是24进制，一周又有7天，一月又有28到31天不等，等等。这就给我们处理时间问题带来了麻烦。为了更好地表达现实世界中的时间，计算机设计者提出了一些概念来进行表达。\n",
    "\n",
    "### 固定时间\n",
    "这个非常简单，它是一个独立的时间，不在任何周期时，比如中午 13:30 睡觉，不代表你每半个小时就睡一次。其他的如，2020 年、农历四月十八、19世纪等等。\n",
    "\n",
    "固定的时间有一定的属性，如所在年、月、日、毫秒等。\n",
    "\n",
    "### 时间戳 timestamp\n",
    "Unix时间戳(Unix timestamp)，时间戳是指格林威治时间1970年01月01日00时00分00秒起至当下的总秒数。它是一个非常大的数字，一直以一秒的步长在增加。如：1591684854 代表北京时间 2020/6/9 14:40:54。那么 1970年 年以前的时间怎么表示呢？用负数，如-1591684957 代表1919/7/26 2:17:23。\n",
    "\n",
    "### 时长时差 Time deltas\n",
    "代表一个时间长度，但它没有指定的开始时间和结束时间，比如一首歌4分钟，你不管从什么时候开始，它都会占用4分钟。\n",
    "\n",
    "### 格式化时间\n",
    "由于原始时间数据可能是时间戳，也有可能是其他类型的数据，我们在使用时想按照一定的格式进行显示，就需要做格式化处理。如时间戳 1591684854 和 2020/6/9 14:40:54 转换为为 2020年06月09日 这样的中文格式。\n",
    "\n",
    "### 周期时间\n",
    "有开始、有结束，并且有时间单位周期的时间，比如从大学毕业后，我开始工作，每周一到周五去工作，持续到65岁退休，这个就是工作日周期。另如钟表，每半小时响一次，开始时间是我安装好它，结束时间是它坏掉的时候。\n",
    "\n",
    "### 日期偏移 Date offsets\n",
    "周期时间中有一个频率，一个频率是一个单位，日期偏移是基于这个频率，如一个周期的频率是小时，那偏移三个频率就是三小时。比如偏移一个工作周，这个工作周期是自己定义的。\n",
    "\n",
    "### 时区\n",
    "每个固定的时间都会有一个时区，一般为你电脑本地的时区，当然你根据需要可以进行调整。\n",
    "\n",
    "### 工作日\n",
    "在数据分析时，经常会与是否工作日相关，除了正常的周末，每个国家和地区节假日，甚至具体到一些公司都会有一些特定的作息，一般需要自己来指定这个工作日的周期。\n",
    "\n",
    "### 时间转换\n",
    "时间转换包括时间表达格式的转换，也会有一些时间计算，比如给一个时间，转为去年的当天、100天前的当天、转换为特定时区的时间等等。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第二部分：时序数据类型\n",
    "时间序列（Time series）数据是非常重要的数据类型，在各个领域的研究中，都与时间相关，因此对于时间数据的处理就越来越重要。Pandas 提供了多种时间数据类型和处理方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. 四类时间序列变量\n",
    "\n",
    "| 时间概念                  | 类型表示       | Array 类       | pandas 类型                          | 创建方法                        |\n",
    "| --------------------- | ---------- | -------------- | ------------------------------------ | ------------------------------- |\n",
    "| 固定时间 (Date times)   | Timestamp  | DatetimeIndex  | datetime64[ns] or datetime64[ns, tz] | to_datetime or date_range       |\n",
    "| 时长 (Time deltas)      | Timedelta  | TimedeltaIndex | timedelta64[ns]                      | to_timedelta or timedelta_range |\n",
    "| 周期 （Time spans）       | Period     | PeriodIndex    | period[freq]                         | Period or period_range          |\n",
    "| 日期偏移 （Date offsets） | DateOffset | None           | None                                 | DateOffset                      |\n",
    "\n",
    "通常时间序列数据作为 Series 或 DataFrame 的索引，以方便对时间数据进行操作。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2 固定时间的创建\n",
    "带时间戳的数据是时间序列数据的最基本类型，它将值与时间点相关联，对它可以进行相关的时间操作，如何定义转换当非常关键。同时一个具体的时间包含了非常丰富的信息，如年份、在周几、在几月、在哪个季度，需要我们进行属性的读取。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 定义一个时间\n",
    "pd.Timestamp() 是定义时间的主要函数，代替 python 中的 datetime.datetime 对象。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "导入相关模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用 python 的 datetime 库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 00:00:00')"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import datetime\n",
    "# 至少需要年月日\n",
    "pd.Timestamp(datetime.datetime(2021, 2, 1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:39:32')"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 指定是时分秒\n",
    "pd.Timestamp(datetime.datetime(2021, 2, 1, 18, 39, 32))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 指定时间字符串"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2018-08-01 00:00:00')"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp('2018-08-01')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-01-01 12:00:00')"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp('2021-01-01T12')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 指定时间位置数字\n",
    "可以依次定义 year, month, day，hour, minute, second, microsecond："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2008-08-08 00:00:00')"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp(2008, 8, 8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2008-08-08 08:00:00')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp(2008, 8, 8, 8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2008-08-08 08:00:00')"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp(year=2008, month=8, day=8, hour=8)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 解析时间戳"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 10:43:26.200000048')"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp(1612176206.2, unit='s') # 单位为秒"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 指定时区"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 02:43:26-0800', tz='US/Pacific')"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp(1612176206, unit='s', tz='US/Pacific')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:43:26+0800', tz='Asia/Shanghai')"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 指定为北京时间\n",
    "pd.Timestamp(1612176206, unit='s', tz='Asia/Shanghai')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 特殊时间\n",
    "以下可取得当前时间，从而可通过属性取到今天日期、年份等信息："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:46:09.627130')"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp('today')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:46:15.060057')"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp('now')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "datetime.date(2021, 2, 1)"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp('today').date() # 只取日期"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "也可以计算出昨天、明天等信息："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-01-31 18:46:50.276669')"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 昨天\n",
    "pd.Timestamp('now')-pd.Timedelta(days=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-02 18:46:56.115898')"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 明天\n",
    "pd.Timestamp('now')+pd.Timedelta(days=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:47:07.699907')"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 当月初，一日\n",
    "pd.Timestamp('now').replace(day=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 时间限制\n",
    "由于 Pandas 以纳秒粒度表示时间戳，因此可以使用64位整数表示的时间跨度限制为大约584年："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('1677-09-21 00:12:43.145225')"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp.min"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2262-04-11 23:47:16.854775807')"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp.max"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上为支持的最早最晚时间。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. 时间属性操作\n",
    "一个具体的时间包含了非常丰富的信息，如年份、在周几、在几月、在哪个季度，需要我们进行属性的读取。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 时间的属性 Attributes\n",
    "我们先定义一个当前时间："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:50:17.041362')"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time = pd.Timestamp('now')\n",
    "time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "numpy.datetime64('2021-02-01T18:50:17.041362000')"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time.asm8 # 返回 numpy datetime64格式（以纳秒为单位）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "其他属性：\n",
    "- time.dayofweek # 周几，周一为0\n",
    "- time.day_of_week # 同上\n",
    "- time.dayofyear #  一年的第几天\n",
    "- time.day_of_year # 同上\n",
    "- time.days_in_month # 当月有多少天\n",
    "- time.daysinmonth # 同上\n",
    "- time.freqstr # 周期字符\n",
    "- time.is_leap_year # 是否闰年，公历的\n",
    "- time.is_month_end #  是否当月最后一天\n",
    "- time.is_month_start # 是否当月第一天\n",
    "- time.is_quarter_end # 是否当季最后一天\n",
    "- time.is_quarter_start # 是否当季第一天\n",
    "- time.is_year_end # 是否当年最后一天\n",
    "- time.is_year_start # 是否当年第一天\n",
    "- time.quarter # 当前季度数\n",
    "- time.tz # 当前时区别名\n",
    "- time.week # 当年第几周\n",
    "- time.weekofyear # 同上\n",
    "- time.day #  日\n",
    "- time.fold\n",
    "- time.freq # 频度周期\n",
    "- time.hour # 时\n",
    "- time.microsecond # 微秒\n",
    "- time.minute # 分\n",
    "- time.month # 月\n",
    "- time.nanosecond # 纳秒\n",
    "- time.second # 秒\n",
    "- time.tzinfo # None\n",
    "- time.value # 时间戳\n",
    "- time.year # 年"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 时间的方法 Methods\n",
    "取一个当前时间，并指定时区为北京时间："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:55:06.578998+0800', tz='Asia/Shanghai')"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time = pd.Timestamp('now', tz='Asia/Shanghai')\n",
    "time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 10:55:06.578998+0000', tz='UTC')"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 转换为指定时区\n",
    "time.astimezone('UTC')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:55:07+0800', tz='Asia/Shanghai')"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 转换单位，向上舍入\n",
    "time.ceil('s') # 转为以秒为单位"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 19:00:00+0800', tz='Asia/Shanghai')"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time.ceil('ns') # 转为以纳秒为单位\n",
    "time.ceil('d') # 保留日\n",
    "time.ceil('h') # 保留时"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:00:00+0800', tz='Asia/Shanghai')"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 转换单位, 为向下舍入\n",
    "time.floor('h') # 保留时"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 19:00:00+0800', tz='Asia/Shanghai')"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 类似四舍五入\n",
    "time.round('h') # 保留时"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Monday'"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 返回星期名\n",
    "time.day_name()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 月份名称\n",
    "time.month_name() # 'June'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 00:00:00+0800', tz='Asia/Shanghai')"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 将时间戳规范化为午夜，保留tz信息。\n",
    "time.normalize()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2019-02-01 18:55:06.578998+0800', tz='Asia/Shanghai')"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 时间元素替换 datetime.replace，可处理纳秒。\n",
    "time.replace(year=2019) # 年份换为2019年"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-08-01 18:55:06.578998+0800', tz='Asia/Shanghai')"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time.replace(month=8) # 月份换为8月"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "<ipython-input-38-1ba4d122f88a>:2: UserWarning: Converting to Period representation will drop timezone information.\n",
      "  time.to_period(freq='h') # 周期为小时\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Period('2021-02-01 18:00', 'H')"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 转为周期类型，将丢失时区\n",
    "time.to_period(freq='h') # 周期为小时"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 10:55:06.578998+0000', tz='UTC')"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 转为指定时区\n",
    "time.tz_convert('UTC') # 转为 utc 时间"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:58:00.359104+0800', tz='Asia/Shanghai')"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 本地化时区转换\n",
    "time = pd.Timestamp('now')\n",
    "time.tz_localize('Asia/Shanghai')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2021-02-01 18:58:00.359104')"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Timestamp('2020-06-09 17:32:47.388726+0800', tz='Asia/Shanghai')\n",
    "time.tz_localize(None) # 删除时区"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### .dt 时间访问器\n",
    "对于时间序列数据，可以使用 s.dt.xxx 的形式来访问它们的属性和调用它们的方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "s = pd.Series(pd.date_range('2020-01-01', periods=3, freq='d'))\n",
    "s.dt.date\n",
    "s.dt.time\n",
    "s.dt.timetz\n",
    "s.dt.year\n",
    "s.dt.month\n",
    "s.dt.day\n",
    "s.dt.hour\n",
    "s.dt.minute\n",
    "s.dt.second\n",
    "s.dt.microsecond\n",
    "s.dt.nanosecond\n",
    "s.dt.week\n",
    "s.dt.weekofyear\n",
    "s.dt.dayofweek\n",
    "s.dt.weekday\n",
    "s.dt.dayofyear\n",
    "s.dt.quarter\n",
    "s.dt.is_month_start\n",
    "s.dt.is_month_end\n",
    "s.dt.is_quarter_start\n",
    "s.dt.is_quarter_end\n",
    "s.dt.is_year_start\n",
    "s.dt.is_year_end\n",
    "s.dt.is_leap_year\n",
    "s.dt.daysinmonth\n",
    "s.dt.days_in_month\n",
    "s.dt.tz\n",
    "s.dt.freq\n",
    "s.dt.to_period\n",
    "s.dt.to_pydatetime\n",
    "s.dt.tz_localize\n",
    "s.dt.tz_convert\n",
    "s.dt.normalize\n",
    "s.dt.strftime\n",
    "s.dt.round\n",
    "s.dt.floor\n",
    "s.dt.ceil\n",
    "s.dt.month_name\n",
    "s.dt.day_name\n",
    "s.dt.qyear\n",
    "s.dt.start_time\n",
    "s.dt.end_time\n",
    "s.dt.days\n",
    "s.dt.seconds\n",
    "s.dt.microseconds\n",
    "s.dt.nanoseconds\n",
    "s.dt.components\n",
    "s.dt.to_pytimedelta\n",
    "s.dt.total_seconds\n",
    "\n",
    "# 个别用法举例\n",
    "s.dt.tz_localize('UTC').dt.tz_convert('US/Eastern')\n",
    "s.dt.strftime('%Y/%m/%d')\n",
    "```\n",
    "对于固定时间会返回固定的结果，对于这序列会返回对应值的序列。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. 时间类型转换\n",
    "由于时间格式样式比较多，很多情况下 Padnas 并不能自动识别为时间类型，所以我们在处理前的数据清洗过程中，需要专门对数据进行时间类型转换。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### astype 转换\n",
    "astype 是最简单的时间转换方法，它只能针对相对标准的时间格式，如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0   2020-01-31\n",
       "1   2020-02-29\n",
       "2   2020-03-31\n",
       "dtype: datetime64[ns]"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = pd.Series(['2020-01-31', '2020-02-29', '2020-03-31'])\n",
    "s.astype('datetime64[ns]')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "指定时区"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0   2020-01-31 00:00:00-05:00\n",
       "1   2020-02-29 00:00:00-05:00\n",
       "2   2020-03-31 00:00:00-04:00\n",
       "dtype: datetime64[ns, US/Eastern]"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.astype('datetime64[ns, US/Eastern]')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 转为时间 to_datetime\n",
    "Pandas 提供的 pd.to_datetime() 是识别转换时间的主要工具。接下来我们看一些例子。\n",
    "\n",
    "从 DataFrame 的多个列中组合一个日期时间。 键可以是常见的缩写，例如['year'，'month'，'day'，'minute'，'second'，'ms'，'us'，'ns']）：\n",
    "\n",
    "- 必须: year, month, day\n",
    "- 可选: hour, minute, second, millisecond, microsecond, nanosecond"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>year</th>\n",
       "      <th>month</th>\n",
       "      <th>day</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2020</td>\n",
       "      <td>2</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2021</td>\n",
       "      <td>3</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   year  month  day\n",
       "0  2020      2    4\n",
       "1  2021      3    5"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.DataFrame({'year': [2020, 2021],\n",
    "                   'month': [2, 3],\n",
    "                   'day': [4, 5]})\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0   2020-02-04\n",
       "1   2021-03-05\n",
       "dtype: datetime64[ns]"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.to_datetime(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0   2020-02-04\n",
       "1   2021-03-05\n",
       "dtype: datetime64[ns]"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.to_datetime(df[['year', 'month', 'day']]) # 同上"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "智能解析时间："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0   2008-12-31\n",
       "1   2018-01-10\n",
       "2          NaT\n",
       "dtype: datetime64[ns]"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.to_datetime(pd.Series(['Dec 31, 2008', '2018-01-10', None]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2005-11-23', '2010-12-31'], dtype='datetime64[ns]', freq=None)"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.to_datetime(['2005/11/23', '2010.12.31'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2012-01-04 10:00:00'], dtype='datetime64[ns]', freq=None)"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.to_datetime(['04-01-2012 10:00'], dayfirst=True) # 日期在前"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以使用 pd.Timestamp() 进行转换："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2010-11-12 00:00:00')"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.to_datetime('2010/11/12')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2010-11-12 00:00:00')"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp('2010/11/12')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "pd.DatetimeIndex 也可以转换："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], dtype='datetime64[ns]', freq=None)"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], dtype='datetime64[ns]', freq='2D')"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.DatetimeIndex(['2018-01-01', '2018-01-03', '2018-01-05'], freq='infer')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于有格式的数据，需要指定数据的格式："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "pd.to_datetime('13000101', format='%Y%m%d', errors='ignore')\n",
    "# 可以让系统自己推断时间格式\n",
    "pd.to_datetime('13000101', infer_datetime_format=True, errors='ignore')\n",
    "# datetime.datetime(1300, 1, 1, 0, 0)\n",
    "# coerce 将不会忽略错误，返回空值\n",
    "pd.to_datetime('13000101', format='%Y%m%d', errors='coerce')\n",
    "# NaT\n",
    "\n",
    "# 有时间需要字段转为字符\n",
    "pd.to_datetime(df.d.astype(str), format='%m/%d/%Y')\n",
    "\n",
    "# 其他\n",
    "pd.to_datetime('2010/11/12', format='%Y/%m/%d')\n",
    "# Timestamp('2010-11-12 00:00:00')\n",
    "\n",
    "pd.to_datetime('12-11-2010 00:00', format='%d-%m-%Y %H:%M')\n",
    "# Timestamp('2010-11-12 00:00:00')\n",
    "对时间戳进行转换，需要给出时间单位，一般为秒：\n",
    "\n",
    "pd.to_datetime(1490195805, unit='s')\n",
    "# Timestamp('2017-03-22 15:16:45')\n",
    "pd.to_datetime(1490195805433502912, unit='ns')\n",
    "# Timestamp('2017-03-22 15:16:45.433502912')\n",
    "对周期数据进行转换：\n",
    "\n",
    "pd.to_datetime([1, 2, 3], unit='D',\n",
    "               origin=pd.Timestamp('1960-01-01'))\n",
    "# DatetimeIndex(['1960-01-02', '1960-01-03', '1960-01-04'], dtype='datetime64[ns]', freq\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 日期格式化符号\n",
    "python中时间日期格式化符号：\n",
    "\n",
    "- %y 两位数的年份表示（00-99）  \n",
    "- %Y 四位数的年份表示（000-9999）  \n",
    "- %m 月份（01-12）\n",
    "- %d 月内中的一天（0-31）\n",
    "- %H 24小时制小时数（0-23）\n",
    "- %I 12小时制小时数（01-12）\n",
    "- %M 分钟数（00-59）\n",
    "- %S 秒（00-59）\n",
    "- %a 本地简化星期名称\n",
    "- %A 本地完整星期名称\n",
    "- %b 本地简化的月份名称\n",
    "- %B 本地完整的月份名称\n",
    "- %c 本地相应的日期表示和时间表示\n",
    "- %j 年内的一天（001-366）\n",
    "- %p 本地A.M.或P.M.的等价符\n",
    "- %U 一年中的星期数（00-53）星期天为星期的开始\n",
    "- %w 星期（0-6），星期天为星期的开始\n",
    "- %W 一年中的星期数（00-53）星期一为星期的开始\n",
    "- %x 本地相应的日期表示\n",
    "- %X 本地相应的时间表示\n",
    "- %Z 当前时区的名称\n",
    "- %% %号本身"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. 时间范围\n",
    "时间周期的特点是有开始时间有结束时间，也会有一个周期频率（虽然有时候也会没有），广泛应用在经济、物理、金融等领域。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 生成时间范围\n",
    "可以使用 pd.DatetimeIndex() 和 pd.Index() 来构造时间范围数据："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2012-05-01', '2012-05-02', '2012-05-03'], dtype='datetime64[ns]', freq=None)"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dates = [datetime.datetime(2012, 5, 1),\n",
    "         datetime.datetime(2012, 5, 2),\n",
    "         datetime.datetime(2012, 5, 3)]\n",
    "\n",
    "# 无频率\n",
    "pd.DatetimeIndex(dates)\n",
    "# pd.Index(dates) # 效果同上"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',\n",
       "               '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'],\n",
       "              dtype='datetime64[ns]', freq='D')"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.date_range(start='1/1/2018', end='1/08/2018')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',\n",
       "               '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'],\n",
       "              dtype='datetime64[ns]', freq='D')"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.date_range(start='1/1/2018', periods=8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2017-12-25', '2017-12-26', '2017-12-27', '2017-12-28',\n",
       "               '2017-12-29', '2017-12-30', '2017-12-31', '2018-01-01'],\n",
       "              dtype='datetime64[ns]', freq='D')"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.date_range(end='1/1/2018', periods=8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2018-04-24 00:00:00', '2018-04-25 12:00:00',\n",
       "               '2018-04-27 00:00:00'],\n",
       "              dtype='datetime64[ns]', freq=None)"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.date_range(start='2018-04-24', end='2018-04-27', periods=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "date_range 的默认频率是 D 日，可以指定为其他频率，"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31', '2018-04-30',\n",
       "               '2018-05-31'],\n",
       "              dtype='datetime64[ns]', freq='M')"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 指定频率为月\n",
    "pd.date_range(start='1/1/2018', periods=5, freq='M')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 固定频率 date_range\n",
    "在实际使用中，我们只需要给出开始和结束时间和频率，pd.date_range 系统会快速生成时间范围数据："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04',\n",
       "               '2011-01-05', '2011-01-06', '2011-01-07', '2011-01-08',\n",
       "               '2011-01-09', '2011-01-10',\n",
       "               ...\n",
       "               '2011-12-23', '2011-12-24', '2011-12-25', '2011-12-26',\n",
       "               '2011-12-27', '2011-12-28', '2011-12-29', '2011-12-30',\n",
       "               '2011-12-31', '2012-01-01'],\n",
       "              dtype='datetime64[ns]', length=366, freq='D')"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "start = datetime.datetime(2011, 1, 1)\n",
    "end = datetime.datetime(2012, 1, 1)\n",
    "pd.date_range(start, end)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "多个单位频率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2018-01-31', '2018-04-30', '2018-07-31', '2018-10-31',\n",
       "               '2019-01-31'],\n",
       "              dtype='datetime64[ns]', freq='3M')"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 三个月\n",
    "pd.date_range(start='1/1/2018', periods=5, freq='3M')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "频率也可以使用时间偏移"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2018-01-31', '2018-04-30', '2018-07-31', '2018-10-31',\n",
       "               '2019-01-31'],\n",
       "              dtype='datetime64[ns]', freq='3M')"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 三个月，取月最后一天\n",
    "pd.date_range(start='1/1/2018', periods=5, freq=pd.offsets.MonthEnd(3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以指定时区："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2018-01-01 00:00:00+09:00', '2018-01-02 00:00:00+09:00',\n",
       "               '2018-01-03 00:00:00+09:00', '2018-01-04 00:00:00+09:00',\n",
       "               '2018-01-05 00:00:00+09:00'],\n",
       "              dtype='datetime64[ns, Asia/Tokyo]', freq='D')"
      ]
     },
     "execution_count": 73,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 东京时间\n",
    "pd.date_range(start='1/1/2018', periods=5, tz='Asia/Tokyo')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "closed 可以做开始和结束时间开闭区间的控制："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04'], dtype='datetime64[ns]', freq='D')"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# None 两边都包含\n",
    "pd.date_range(start='2017-01-01', end='2017-01-04', closed=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03'], dtype='datetime64[ns]', freq='D')"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# left 不包含右边\n",
    "pd.date_range(start='2017-01-01', end='2017-01-04', closed='left')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2017-01-02', '2017-01-03', '2017-01-04'], dtype='datetime64[ns]', freq='D')"
      ]
     },
     "execution_count": 76,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# right 不包含左边\n",
    "pd.date_range(start='2017-01-01', end='2017-01-04', closed='right')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 工作日频率 bdate_range\n",
    "pd.bdate_range 可以生成一个以工作日频率的日期范围，周末两天将会被跳过："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2021-01-01', '2021-01-04', '2021-01-05', '2021-01-06',\n",
       "               '2021-01-07', '2021-01-08'],\n",
       "              dtype='datetime64[ns]', freq='B')"
      ]
     },
     "execution_count": 77,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.bdate_range(start='1/1/2021', end='1/08/2021')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在四个参数中：开始，结束，周期和频率，必须精确指定三个。 指定频率是 bdate_range 的要求。 如果不需要指定频率，请使用 date_range。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 频率\n",
    "以上两个方法中都会要求传入频率，频率可以用时间偏移对象（DateOffset objects）的别名表示。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. 时间偏移\n",
    "周期数据有一个基础频率，或者叫分辨率、粒度，时间偏移由基础频率和乘数组成，这对我们处理周期数据非常有用。  \n",
    "Pandas 专门提供了一个时间偏移对象（Date offsets）来完成时间偏移工作，本文将介绍 Date offsets 的构成和使用方法。DateOffset 基础操作类似于 dateutil.relativedelta（relativedelta 文档），可以按真实的日历进行时间偏移，并用算数运算符（+）或 apply 进行日期偏移操作。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### DateOffset 对象\n",
    "DateOffset 类似于时间差 Timedelta ，但它使用日历中时间日期的规则，而不是直接进行时间性质的算术计算，让时间更符合实际生活。比如，有些地区使用夏令时时，每日偏移时间有可能是 23 或 24 小时，甚至 25 个小时。  \n",
    "**DataOffset与Timedelta的区别**  \n",
    "- Timedelta绝对时间差的特点指无论是冬令时还是夏令时，增减1day都只计算24小时\n",
    "- DataOffset相对时间差指，无论一天是23\\24\\25小时，增减1day都与当天相同的时间保持一致"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### DateOffset 示例\n",
    "以下所示了夏令时的情况："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 122,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2016-10-30 00:00:00+0300', tz='Europe/Helsinki')"
      ]
     },
     "execution_count": 122,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 生成一个指定的时间，芬兰赫尔辛基时间执行夏令时\n",
    "ts = pd.Timestamp('2016-10-30 00:00:00', tz='Europe/Helsinki')\n",
    "ts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 125,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2016-10-30 23:00:00+0200', tz='Europe/Helsinki')"
      ]
     },
     "execution_count": 125,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 增加一天\n",
    "ts + pd.Timedelta(days=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 126,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2016-10-31 00:00:00+0200', tz='Europe/Helsinki')"
      ]
     },
     "execution_count": 126,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 按日历时间\n",
    "ts + pd.DateOffset(days=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这似乎有些令人头大，但只要把tz（time zone）去除就可以不用管它了，两者保持一致，除非要使用到时区变换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2016-10-31 00:00:00')"
      ]
     },
     "execution_count": 143,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 增加一天\n",
    "ts + pd.Timedelta(days=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 144,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2016-10-31 00:00:00')"
      ]
     },
     "execution_count": 144,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 按日历时间\n",
    "ts + pd.DateOffset(days=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以下是增加工作日，出现跨周末的情况："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 142,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2016-10-30 00:00:00')"
      ]
     },
     "execution_count": 142,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 生成一个指定的时间，芬兰赫尔辛基时间执行夏令时\n",
    "ts = pd.Timestamp('2016-10-30 00:00:00')\n",
    "ts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 127,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Friday'"
      ]
     },
     "execution_count": 127,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "friday = pd.Timestamp('2018-01-05')\n",
    "friday.day_name()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2018-01-09 00:00:00')"
      ]
     },
     "execution_count": 128,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 增加两个工作日，从周五到周二\n",
    "two_business_days = 2 * pd.offsets.BDay()\n",
    "two_business_days.apply(friday)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 130,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2018-01-09 00:00:00')"
      ]
     },
     "execution_count": 130,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "friday + two_business_days"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 131,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Tuesday'"
      ]
     },
     "execution_count": 131,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(friday + two_businbess_days).day_name()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 增减一段时间\n",
    "DateOffset的可选参数包括years/months/weeks/days/hours/minutes/seconds  \n",
    "所有的日期偏移对象都在 pandas.tseries.offsets 下，其中 pandas.tseries.offsets.DateOffset 是标准的日期范围时间偏移类型，用于日期范围的标准日期增量类型。它默认是一个日历日。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 132,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2017-04-01 09:10:11')"
      ]
     },
     "execution_count": 132,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts = pd.Timestamp('2017-01-01 09:10:11')\n",
    "ts + pd.DateOffset(months=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 133,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2017-01-01 11:10:11')"
      ]
     },
     "execution_count": 133,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts + pd.DateOffset(hours=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 134,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2017-01-02 09:10:11')"
      ]
     },
     "execution_count": 134,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts + pd.DateOffset()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 各类常用offset对象\n",
    "\n",
    "| freq   | D/B             | W    | (B)M/(B)Q/(B)Y                       | (B)MS/(B)QS/(B)YS                          | H    | T    | S    | C    |\n",
    "| ------ | --------------- | ---- | ------------------------------------ | ------------------------------------------ | ---- | ---- | ---- | ---- |\n",
    "| offset | DateOffset/BDay | Week | (B)MonthEnd/(B)QuarterEnd/(B)YearEnd | (B)MonthBegin/(B)QuarterBegin/(B)YearBegin | Hour | Min  |      |      |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 145,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2020-01-15 00:00:00')"
      ]
     },
     "execution_count": 145,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp('2020-01-01') + pd.offsets.Week(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 146,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2020-03-02 00:00:00')"
      ]
     },
     "execution_count": 146,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.Timestamp('2020-01-01') + pd.offsets.BQuarterBegin(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 频率字符串\n",
    "DateOffset 基本都支持频率字符串或偏移别名，传入 freq 参数。以下都是时间偏移的子类、子对象，都支持时间偏移的相关操作。有效的日期偏移及频率字符串有：\n",
    "\n",
    "| 日期偏移对象                             | 频率字符串    | 说明                                       |\n",
    "| ---------------------------------------- | ------------- | ------------------------------------------ |\n",
    "| DateOffset                               | 无            | 通用偏移类，默认一个日历日                 |\n",
    "| BDay 或 BusinessDay                      | 'B'           | 工作日                                     |\n",
    "| CDay 或 CustomBusinessDay                | 'C'           | 自定义工作日                               |\n",
    "| Week                                     | 'W'           | 一周，可选周内固定某日                     |\n",
    "| WeekOfMonth                              | 'WOM'         | 每月第几周的第几天                         |\n",
    "| LastWeekOfMonth                          | 'LWOM'        | 每月最后一周的第几天                       |\n",
    "| MonthEnd                                 | 'M'           | 日历日月末                                 |\n",
    "| MonthBegin                               | 'MS'          | 日历日月初                                 |\n",
    "| BMonthEnd 或 BusinessMonthEnd            | 'BM'          | 工作日月末                                 |\n",
    "| BMonthBegin 或 BusinessMonthBegin        | 'BMS'         | 工作日月初                                 |\n",
    "| CBMonthEnd 或 CustomBusinessMonthEnd     | 'CBM'         | 自定义工作日月末                           |\n",
    "| CBMonthBegin 或 CustomBusinessMonthBegin | 'CBMS'        | 自定义工作日月初                           |\n",
    "| SemiMonthEnd                             | 'SM'          | 某月第 15 天（或其它半数日期）与日历日月末 |\n",
    "| SemiMonthBegin                           | 'SMS'         | 日历日月初与第 15 天（或其它半数日期）     |\n",
    "| QuarterEnd                               | 'Q'           | 日历日季末                                 |\n",
    "| QuarterBegin                             | 'QS'          | 日历日季初                                 |\n",
    "| BQuarterEnd                              | 'BQ           | 工作日季末                                 |\n",
    "| BQuarterBegin                            | 'BQS'         | 工作日季初                                 |\n",
    "| FY5253Quarter                            | 'REQ'         | 零售季，又名 52-53 周                      |\n",
    "| YearEnd                                  | 'A'           | 日历日年末                                 |\n",
    "| YearBegin                                | 'AS' 或 'BYS' | 日历日年初                                 |\n",
    "| BYearEnd                                 | 'BA'          | 工作日年末                                 |\n",
    "| BYearBegin                               | 'BAS'         | 工作日年初                                 |\n",
    "| FY5253                                   | 'RE'          | 零售年（又名 52-53 周）                    |\n",
    "| Easter                                   | 无            | 复活节假日                                 |\n",
    "| BusinessHour                             | 'BH'          | 工作小时                                   |\n",
    "| CustomBusinessHour                       | 'CBH'         | 自定义工作小时                             |\n",
    "| Day                                      | 'D'           | 一天                                       |\n",
    "| Hour                                     | 'H'           | 一小时                                     |\n",
    "| Minute                                   | 'T' 或 'min'  | 一分钟                                     |\n",
    "| Second                                   | 'S'           | 一秒                                       |\n",
    "| Milli                                    | 'L' 或 'ms'   | 一毫秒                                     |\n",
    "| Micro                                    | 'U' 或 'us'   | 一微秒                                     |\n",
    "| Nano                                     | 'N'           | 一纳秒                                     |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 移动偏移\n",
    "Offset 支持向前或向后偏移：\n",
    "```python\n",
    "ts = pd.Timestamp('2020-06-06 00:00:00')\n",
    "ts.day_name()\n",
    "# 'Saturday'\n",
    "\n",
    "# 定义一个工作小时偏移，默认是周一到周五 9-17 点，我们从 10点开始\n",
    "offset = pd.offsets.BusinessHour(start='10:00')\n",
    "\n",
    "# 向前偏移一个工作小时，是一个周一，跳过了周日\n",
    "offset.rollforward(ts)\n",
    "# Timestamp('2020-06-08 10:00:00')\n",
    "\n",
    "# 向前偏移至最近的工作日，小时也会增加\n",
    "ts + offset\n",
    "# Timestamp('2020-06-08 11:00:00')\n",
    "\n",
    "# 向后偏移，会在周五下班前的一个小时\n",
    "offset.rollback(ts)\n",
    "# Timestamp('2020-06-05 17:00:00')\n",
    "\n",
    "ts - pd.offsets.Day(1) # 昨日\n",
    "ts - pd.offsets.Day(2) # 前日\n",
    "ts - pd.offsets.Week(weekday=0) - pd.offsets.Day(14) # 上周一\n",
    "ts - pd.offsets.MonthEnd() - pd.offsets.MonthBegin() # 上月一日\n",
    "时间偏移操作会保留小时和分钟，有时候我们不在意具体的时间只开始从哪天开始，可以使用 normalize() 进行标准化到午夜 0 点：\n",
    "\n",
    "offset.rollback(ts).normalize()\n",
    "# Timestamp('2020-06-05 00:00:00')\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 应用偏移\n",
    "```python\n",
    "apply 可以使用偏移对象应用到一个时间上：\n",
    "\n",
    "ts = pd.Timestamp('2020-06-01 09:00')\n",
    "day = pd.offsets.Day() # 定义偏移对象\n",
    "day.apply(ts) # 偏移对象应用到时间上\n",
    "# Timestamp('2020-06-02 09:00:00')\n",
    "day.apply(ts).normalize() # 标准化/归一化\n",
    "# Timestamp('2020-06-02 00:00:00')\n",
    "\n",
    "ts = pd.Timestamp('2020-06-01 22:00')\n",
    "hour = pd.offsets.Hour()\n",
    "hour.apply(ts)\n",
    "# Timestamp('2020-06-01 23:00:00')\n",
    "\n",
    "hour.apply(ts).normalize()\n",
    "# Timestamp('2020-06-01 00:00:00')\n",
    "\n",
    "hour.apply(pd.Timestamp(\"2014-01-01 23:30\")).normalize()\n",
    "# Timestamp('2014-01-02 00:00:00')\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 偏移参数\n",
    "上边我们偏移时只偏移了偏移对象的一个单位，可以传入参数支持多个单位和对象中的其他单位：\n",
    "```python\n",
    "import datetime\n",
    "d = datetime.datetime(2020, 6, 1, 9, 0)\n",
    "# datetime.datetime(2020, 6, 1, 9, 0)\n",
    "\n",
    "d + pd.offsets.Week() # 偏移一周\n",
    "# Timestamp('2020-06-08 09:00:00')\n",
    "\n",
    "d + pd.offsets.Week(weekday=4) # 偏移4个周中的日期\n",
    "# Timestamp('2020-06-05 09:00:00')\n",
    "\n",
    "# 取一周第几天\n",
    "(d + pd.offsets.Week(weekday=4)).weekday()\n",
    "# 4\n",
    "\n",
    "d - pd.offsets.Week() # 向后一周\n",
    "# Timestamp('2020-05-25 09:00:00')\n",
    "# 参数也支持归一标准化 normalize:\n",
    "\n",
    "d + pd.offsets.Week(normalize=True)\n",
    "# Timestamp('2020-06-08 00:00:00')\n",
    "\n",
    "d - pd.offsets.Week(normalize=True)\n",
    "# Timestamp('2020-05-25 00:00:00')\n",
    "# 再比如，YearEnd 支持 month 指定月份：\n",
    "\n",
    "d + pd.offsets.YearEnd()\n",
    "# Timestamp('2020-12-31 09:00:00')\n",
    "\n",
    "d + pd.offsets.YearEnd(month=6)\n",
    "# Timestamp('2020-06-30 09:00:00')\n",
    "# 不同的偏移对象支持不同的参数，可以通过代码编辑器的代码提示进行查询。\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 相关查询\n",
    "当使用日期作为索引的DataFrame时，此函数可以基于日期偏移量选择最后几行：\n",
    "```python\n",
    "i = pd.date_range('2018-04-09', periods=4, freq='2D')\n",
    "ts = pd.DataFrame({'A': [1, 2, 3, 4]}, index=i)\n",
    "ts\n",
    "'''\n",
    "            A\n",
    "2018-04-09  1\n",
    "2018-04-11  2\n",
    "2018-04-13  3\n",
    "2018-04-15  4\n",
    "'''\n",
    "\n",
    "# 取最后三天, 请注意，返回的是最近3天的数据\n",
    "# 而不是数据集中最近3天的数据，因此未返回2018-04-11的数据\n",
    "ts.last('3D')\n",
    "'''\n",
    "            A\n",
    "2018-04-13  3\n",
    "2018-04-15  4\n",
    "'''\n",
    "\n",
    "# 前三天\n",
    "ts.first('3D')\n",
    "'''\n",
    "            A\n",
    "2018-04-09  1\n",
    "2018-04-11  2\n",
    "'''\n",
    "\n",
    "# 指定时间\n",
    "ts.at_time('12:00')\n",
    "'''\n",
    "                     A\n",
    "2018-04-09 12:00:00  2\n",
    "2018-04-10 12:00:00  4\n",
    "'''\n",
    "\n",
    "ts.between_time('0:15', '0:45')\n",
    "'''\n",
    "                     A\n",
    "2018-04-10 00:20:00  2\n",
    "2018-04-11 00:40:00  3\n",
    "'''\n",
    "\n",
    "ts.between_time('0:45', '0:15')\n",
    "'''\n",
    "                     A\n",
    "2018-04-09 00:00:00  1\n",
    "2018-04-12 01:00:00  4\n",
    "'''\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 序列与时间偏移操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 135,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2012-01-01', '2012-01-02', '2012-01-03'], dtype='datetime64[ns]', freq='D')"
      ]
     },
     "execution_count": 135,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rng = pd.date_range('2012-01-01', '2012-01-03')\n",
    "s = pd.Series(rng)\n",
    "rng"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 136,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2012-03-01', '2012-03-02', '2012-03-03'], dtype='datetime64[ns]', freq=None)"
      ]
     },
     "execution_count": 136,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rng + pd.DateOffset(months=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 137,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0   2012-03-01\n",
       "1   2012-03-02\n",
       "2   2012-03-03\n",
       "dtype: datetime64[ns]"
      ]
     },
     "execution_count": 137,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s + pd.DateOffset(months=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0   2011-11-01\n",
       "1   2011-11-02\n",
       "2   2011-11-03\n",
       "dtype: datetime64[ns]"
      ]
     },
     "execution_count": 138,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s - pd.DateOffset(months=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 与时长的操作\n",
    "时长也支持与时间偏移进行操作，而且和时长与时长的操作一样："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 139,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0   2011-12-30\n",
       "1   2011-12-31\n",
       "2   2012-01-01\n",
       "dtype: datetime64[ns]"
      ]
     },
     "execution_count": 139,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s - pd.offsets.Day(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 140,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0   3 days\n",
       "1   3 days\n",
       "2   3 days\n",
       "dtype: timedelta64[ns]"
      ]
     },
     "execution_count": 140,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "td = s - pd.Series(pd.date_range('2011-12-29', '2011-12-31'))\n",
    "td"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 141,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0   3 days 00:15:00\n",
       "1   3 days 00:15:00\n",
       "2   3 days 00:15:00\n",
       "dtype: timedelta64[ns]"
      ]
     },
     "execution_count": 141,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "td + pd.offsets.Minute(15)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "需要注意的是，有些时间偏移对象不支持以上操作，还有是就算支持性能会很差，执行很慢，会及抛出性能警告。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第三部分：时间序列索引\n",
    "在时间序列数据中，索引经常是时间类型，我们对数据的操作要经常与时间类型索引打交道，本文将介绍如何查询操作时间类型索引。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 时间索引切片\n",
    "DatetimeIndex 作为时间索引，同样也支持数据切片："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2021-01-29    0.494045\n",
       "2021-02-26    0.662493\n",
       "2021-03-31    2.131822\n",
       "2021-04-30   -0.826927\n",
       "2021-05-31   -0.822046\n",
       "2021-06-30   -1.207667\n",
       "2021-07-30    0.993799\n",
       "2021-08-31   -0.711776\n",
       "2021-09-30   -0.617836\n",
       "2021-10-29    0.130349\n",
       "2021-11-30   -0.473077\n",
       "Freq: BM, dtype: float64"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rng = pd.date_range('1/1/2021', '12/1/2021', freq='BM')\n",
    "ts = pd.Series(np.random.randn(len(rng)), index=rng)\n",
    "ts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2021-03-31', '2021-04-30'], dtype='datetime64[ns]', freq='BM')"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts[2:4].index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2021-01-29', '2021-03-31', '2021-05-31', '2021-07-30',\n",
       "               '2021-09-30', '2021-11-30'],\n",
       "              dtype='datetime64[ns]', freq='2BM')"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts[::2].index"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 索引访问\n",
    "以下是几种索引的访问方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.49404517681343435"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts['1/29/2021']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2021-09-30   -0.617836\n",
       "2021-10-29    0.130349\n",
       "2021-11-30   -0.473077\n",
       "Freq: BM, dtype: float64"
      ]
     },
     "execution_count": 85,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts[datetime.datetime(2021, 9, 30):]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2021-05-31   -0.822046\n",
       "2021-06-30   -1.207667\n",
       "2021-07-30    0.993799\n",
       "2021-08-31   -0.711776\n",
       "Freq: BM, dtype: float64"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts['5/31/2021':'8/31/2021']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "也可以使用部分字符查询一定范围的数据\n",
    "```python\n",
    "ts['2021'] # 查询整个2021年的\n",
    "ts['2021-6'] # 查询 2021年6月的\n",
    "ts['2021-6':'2021-10'] # 6月到10月的\n",
    "dft['2013-1':'2013-2-28 00:00:00'] # 精确时间\n",
    "dft['2013-1-15':'2013-1-15 12:30:00']\n",
    "dft2.loc['2013-01-05']\n",
    "# 索引选择器\n",
    "idx = pd.IndexSlice\n",
    "dft2.loc[idx[:, '2013-01-05'], :]\n",
    "# 带时区，原数据时区可能不是这个\n",
    "df['2019-01-01 12:00:00+04:00':'2019-01-01 13:00:00+04:00']\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 频率的分辨率（粒度）\n",
    "在之前的例子中我们看到频率有工作日的，有自然日的，但它们都是以日为单位的，所以日就是他们有的相同的分辨率，也就是最小粒度。可以使用 x.resolution 查看频率的分辨率。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'minute'"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series_minute = pd.Series([1, 2, 3],\n",
    "                          pd.DatetimeIndex(['2011-12-31 23:59:00',\n",
    "                                            '2012-01-01 00:00:00',\n",
    "                                            '2012-01-01 00:02:00']))\n",
    "series_minute.index.resolution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2011-12-31 23:59:00    1\n",
       "dtype: int64"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 按小时取出\n",
    "series_minute['2011-12-31 23']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 90,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series_minute['2011-12-31 23:59']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series_minute['2011-12-31 23:59:00']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2011-12-31 23:59:59    1\n",
       "2012-01-01 00:00:00    2\n",
       "2012-01-01 00:00:01    3\n",
       "dtype: int64"
      ]
     },
     "execution_count": 93,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series_second = pd.Series([1, 2, 3],\n",
    "                          pd.DatetimeIndex(['2011-12-31 23:59:59',\n",
    "                                            '2012-01-01 00:00:00',\n",
    "                                            '2012-01-01 00:00:01']))\n",
    "series_second"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'second'"
      ]
     },
     "execution_count": 94,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 最小粒度为秒\n",
    "series_second.index.resolution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2011-12-31 23:59:59    1\n",
       "dtype: int64"
      ]
     },
     "execution_count": 95,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "series_second['2011-12-31 23:59']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 截断索引\n",
    "df.truncate() 作为一个专门对索引的截取工具，可以很好地应用在时序索引上："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2011-11-06   -0.690541\n",
       "2011-11-13    0.598374\n",
       "2011-11-20    1.781615\n",
       "2011-11-27   -0.950292\n",
       "Freq: W-SUN, dtype: float64"
      ]
     },
     "execution_count": 96,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rng2 = pd.date_range('2011-01-01', '2012-01-01', freq='W')\n",
    "ts2 = pd.Series(np.random.randn(len(rng2)), index=rng2)\n",
    "ts2.truncate(before='2011-11', after='2011-12')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2011-11-06   -0.690541\n",
       "2011-11-13    0.598374\n",
       "2011-11-20    1.781615\n",
       "2011-11-27   -0.950292\n",
       "2011-12-04    0.220030\n",
       "2011-12-11    0.519082\n",
       "2011-12-18   -0.974609\n",
       "2011-12-25    0.413335\n",
       "Freq: W-SUN, dtype: float64"
      ]
     },
     "execution_count": 97,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 对比以上操作的不同\n",
    "ts2['2011-11':'2011-12']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "DatetimeIndex(['2011-01-02', '2011-01-16', '2011-02-13'], dtype='datetime64[ns]', freq=None)"
      ]
     },
     "execution_count": 98,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 也可以通过自然索引来取\n",
    "ts2[[0, 2, 6]].index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "      <th>C</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>a</td>\n",
       "      <td>f</td>\n",
       "      <td>k</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>b</td>\n",
       "      <td>g</td>\n",
       "      <td>l</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>c</td>\n",
       "      <td>h</td>\n",
       "      <td>m</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>d</td>\n",
       "      <td>i</td>\n",
       "      <td>n</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>e</td>\n",
       "      <td>j</td>\n",
       "      <td>o</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   A  B  C\n",
       "1  a  f  k\n",
       "2  b  g  l\n",
       "3  c  h  m\n",
       "4  d  i  n\n",
       "5  e  j  o"
      ]
     },
     "execution_count": 99,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.DataFrame({'A': ['a', 'b', 'c', 'd', 'e'],\n",
    "                   'B': ['f', 'g', 'h', 'i', 'j'],\n",
    "                   'C': ['k', 'l', 'm', 'n', 'o']},\n",
    "                  index=[1, 2, 3, 4, 5])\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "      <th>C</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>b</td>\n",
       "      <td>g</td>\n",
       "      <td>l</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>c</td>\n",
       "      <td>h</td>\n",
       "      <td>m</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>d</td>\n",
       "      <td>i</td>\n",
       "      <td>n</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   A  B  C\n",
       "2  b  g  l\n",
       "3  c  h  m\n",
       "4  d  i  n"
      ]
     },
     "execution_count": 100,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.truncate(before=2, after=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>a</td>\n",
       "      <td>f</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>b</td>\n",
       "      <td>g</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>c</td>\n",
       "      <td>h</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>d</td>\n",
       "      <td>i</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>e</td>\n",
       "      <td>j</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   A  B\n",
       "1  a  f\n",
       "2  b  g\n",
       "3  c  h\n",
       "4  d  i\n",
       "5  e  j"
      ]
     },
     "execution_count": 101,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 按列取\n",
    "df.truncate(before=\"A\", after=\"B\", axis=\"columns\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2    b\n",
       "3    c\n",
       "4    d\n",
       "Name: A, dtype: object"
      ]
     },
     "execution_count": 102,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df['A'].truncate(before=2, after=4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "截取时间的例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2016-01-31 23:59:56</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-31 23:59:57</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-31 23:59:58</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-31 23:59:59</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-02-01 00:00:00</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                     A\n",
       "2016-01-31 23:59:56  1\n",
       "2016-01-31 23:59:57  1\n",
       "2016-01-31 23:59:58  1\n",
       "2016-01-31 23:59:59  1\n",
       "2016-02-01 00:00:00  1"
      ]
     },
     "execution_count": 103,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dates = pd.date_range('2016-01-01', '2016-02-01', freq='s')\n",
    "df = pd.DataFrame(index=dates, data={'A': 1})\n",
    "df.tail()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2016-01-09 23:59:56</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-09 23:59:57</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-09 23:59:58</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-09 23:59:59</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-10 00:00:00</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                     A\n",
       "2016-01-09 23:59:56  1\n",
       "2016-01-09 23:59:57  1\n",
       "2016-01-09 23:59:58  1\n",
       "2016-01-09 23:59:59  1\n",
       "2016-01-10 00:00:00  1"
      ]
     },
     "execution_count": 104,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.truncate(before=pd.Timestamp('2016-01-05'),\n",
    "            after=pd.Timestamp('2016-01-10')).tail()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2016-01-09 23:59:56</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-09 23:59:57</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-09 23:59:58</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-09 23:59:59</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-10 00:00:00</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                     A\n",
       "2016-01-09 23:59:56  1\n",
       "2016-01-09 23:59:57  1\n",
       "2016-01-09 23:59:58  1\n",
       "2016-01-09 23:59:59  1\n",
       "2016-01-10 00:00:00  1"
      ]
     },
     "execution_count": 105,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.truncate('2016-01-05', '2016-01-10').tail()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2016-01-10 23:59:55</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-10 23:59:56</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-10 23:59:57</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-10 23:59:58</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-10 23:59:59</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                     A\n",
       "2016-01-10 23:59:55  1\n",
       "2016-01-10 23:59:56  1\n",
       "2016-01-10 23:59:57  1\n",
       "2016-01-10 23:59:58  1\n",
       "2016-01-10 23:59:59  1"
      ]
     },
     "execution_count": 106,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.loc['2016-01-05':'2016-01-10', :].tail()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第四部分：时间序列方法\n",
    "如同其他类型的数据，时序数据需要做一些汇总、位移、计算等操作。本文将介绍 Pandas 对时序数据的一些处理操作方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 移动 Shifting\n",
    "可能需要将时间序列中的值在时间上前后移动或滞后。 shift() 方法也可以在时序对象上使用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2020-06-01    0\n",
       "2020-06-02    1\n",
       "2020-06-03    2\n",
       "Freq: D, dtype: int64"
      ]
     },
     "execution_count": 107,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rng = pd.date_range('2020-06-01', '2020-06-03')\n",
    "ts = pd.Series(range(len(rng)), index=rng)\n",
    "ts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2020-06-01    NaN\n",
       "2020-06-02    0.0\n",
       "2020-06-03    1.0\n",
       "Freq: D, dtype: float64"
      ]
     },
     "execution_count": 108,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts.shift(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "shift 方法接受 freq 参数，该参数可以接受 DateOffset 类或其他类似 timedelta 的对象,也可以接受偏移别名。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2020-06-04    0\n",
       "2020-06-05    1\n",
       "2020-06-08    2\n",
       "dtype: int64"
      ]
     },
     "execution_count": 109,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 工作日\n",
    "ts.shift(3, freq=pd.offsets.BDay())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2020-08-31    0\n",
       "2020-08-31    1\n",
       "2020-08-31    2\n",
       "dtype: int64"
      ]
     },
     "execution_count": 110,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 工作日月末\n",
    "ts.shift(3, freq='BM')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "除了更改数据和索引的对齐方式之外，ts方法将索引中的所有日期更改指定的偏移量（只移动索引）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2020-06-04    0\n",
       "2020-06-05    1\n",
       "2020-06-06    2\n",
       "Freq: D, dtype: int64"
      ]
     },
     "execution_count": 112,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts.shift(3, freq='D')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "请注意，使用shift时，最前边的 条目将不再是NaN，因为不会重新对齐数据。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 频率转换\n",
    "更改频率的主要功能是 asfreq() 方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2010-01-01    2.367982\n",
       "2010-01-06   -0.047885\n",
       "2010-01-11   -0.528319\n",
       "Freq: 3B, dtype: float64"
      ]
     },
     "execution_count": 113,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dr = pd.date_range('1/1/2010', periods=3, freq=3 * pd.offsets.BDay())\n",
    "ts = pd.Series(np.random.randn(3), index=dr)\n",
    "ts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2010-01-01    2.367982\n",
       "2010-01-04         NaN\n",
       "2010-01-05         NaN\n",
       "2010-01-06   -0.047885\n",
       "2010-01-07         NaN\n",
       "2010-01-08         NaN\n",
       "2010-01-11   -0.528319\n",
       "Freq: B, dtype: float64"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 从3个工作日转为一个工作日\n",
    "ts.asfreq(pd.offsets.BDay())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "asfreq 提供了更多便利，因此您可以为频率转换后可能出现的任何间隙指定插值方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2010-01-01    2.367982\n",
       "2010-01-04    2.367982\n",
       "2010-01-05    2.367982\n",
       "2010-01-06   -0.047885\n",
       "2010-01-07   -0.047885\n",
       "2010-01-08   -0.047885\n",
       "2010-01-11   -0.528319\n",
       "Freq: B, dtype: float64"
      ]
     },
     "execution_count": 115,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts.asfreq(pd.offsets.BDay(), method='pad')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2010-01-01 00:00:00    2.367982\n",
       "2010-01-01 00:00:30    9.000000\n",
       "2010-01-01 00:01:00    9.000000\n",
       "2010-01-01 00:01:30    9.000000\n",
       "2010-01-01 00:02:00    9.000000\n",
       "                         ...   \n",
       "2010-01-10 23:58:00    9.000000\n",
       "2010-01-10 23:58:30    9.000000\n",
       "2010-01-10 23:59:00    9.000000\n",
       "2010-01-10 23:59:30    9.000000\n",
       "2010-01-11 00:00:00   -0.528319\n",
       "Freq: 30S, Length: 28801, dtype: float64"
      ]
     },
     "execution_count": 116,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 对空值进行填充\n",
    "ts.asfreq(freq='30S', fill_value=9.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于 DatetimeIndex，这基本上只是reindex() 的一个很方便的包装器，该包装器生成 date_range 并调用 reindex。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>prices</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2010-01-01</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-02</th>\n",
       "      <td>101.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-03</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-04</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-05</th>\n",
       "      <td>89.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-06</th>\n",
       "      <td>88.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            prices\n",
       "2010-01-01   100.0\n",
       "2010-01-02   101.0\n",
       "2010-01-03     NaN\n",
       "2010-01-04   100.0\n",
       "2010-01-05    89.0\n",
       "2010-01-06    88.0"
      ]
     },
     "execution_count": 117,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "date_index = pd.date_range('1/1/2010', periods=6, freq='D')\n",
    "df2 = pd.DataFrame({\"prices\": [100, 101, np.nan, 100, 89, 88]},\n",
    "                   index=date_index)\n",
    "df2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>prices</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2009-12-29</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2009-12-30</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2009-12-31</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-01</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-02</th>\n",
       "      <td>101.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-03</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-04</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-05</th>\n",
       "      <td>89.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-06</th>\n",
       "      <td>88.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-07</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            prices\n",
       "2009-12-29     NaN\n",
       "2009-12-30     NaN\n",
       "2009-12-31     NaN\n",
       "2010-01-01   100.0\n",
       "2010-01-02   101.0\n",
       "2010-01-03     NaN\n",
       "2010-01-04   100.0\n",
       "2010-01-05    89.0\n",
       "2010-01-06    88.0\n",
       "2010-01-07     NaN"
      ]
     },
     "execution_count": 118,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 假设我们决定扩展数据框以覆盖更大的日期范围\n",
    "date_index2 = pd.date_range('12/29/2009', periods=10, freq='D')\n",
    "df2.reindex(date_index2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "默认情况下，原始数据框中没有值的索引条目（例如，“ 2009-12-29”）将用NaN填充。 如果需要，我们可以使用几个选项之一（{None, ‘backfill’/’bfill’, ‘pad’/’ffill’, ‘nearest’}）来填写缺失值。\n",
    "\n",
    "例如，要反向传播最后一个有效值以填充NaN值，请将 bfill 作为参数传递给method关键字。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>prices</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2009-12-29</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2009-12-30</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2009-12-31</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-01</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-02</th>\n",
       "      <td>101.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-03</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-04</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-05</th>\n",
       "      <td>89.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-06</th>\n",
       "      <td>88.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-07</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            prices\n",
       "2009-12-29   100.0\n",
       "2009-12-30   100.0\n",
       "2009-12-31   100.0\n",
       "2010-01-01   100.0\n",
       "2010-01-02   101.0\n",
       "2010-01-03     NaN\n",
       "2010-01-04   100.0\n",
       "2010-01-05    89.0\n",
       "2010-01-06    88.0\n",
       "2010-01-07     NaN"
      ]
     },
     "execution_count": 119,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df2.reindex(date_index2, method='bfill')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 其他方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([datetime.datetime(2010, 1, 1, 0, 0),\n",
       "       datetime.datetime(2010, 1, 2, 0, 0),\n",
       "       datetime.datetime(2010, 1, 3, 0, 0),\n",
       "       datetime.datetime(2010, 1, 4, 0, 0),\n",
       "       datetime.datetime(2010, 1, 5, 0, 0),\n",
       "       datetime.datetime(2010, 1, 6, 0, 0)], dtype=object)"
      ]
     },
     "execution_count": 120,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# DatetimeIndex 转为 Python 原生 datetime.datetime 类型\n",
    "df2.index.to_pydatetime()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第五部分：时间重采样\n",
    "Pandas 具有简单，强大和高效的功能，可在频率转换期间执行重采样操作（例如，将秒数据转换为5分钟数据）。 这在金融应用程序中非常普遍，但不仅限于此。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 重采样基础使用\n",
    "resample() 是一个基于时间的分组依据，后面是每个分组的聚合方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 172,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00    244\n",
       "2012-01-01 00:00:01    174\n",
       "2012-01-01 00:00:02     18\n",
       "2012-01-01 00:00:03     87\n",
       "2012-01-01 00:00:04    435\n",
       "                      ... \n",
       "2012-01-01 00:16:35     33\n",
       "2012-01-01 00:16:36     72\n",
       "2012-01-01 00:16:37     23\n",
       "2012-01-01 00:16:38    364\n",
       "2012-01-01 00:16:39    308\n",
       "Freq: S, Length: 1000, dtype: int32"
      ]
     },
     "execution_count": 172,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rng = pd.date_range('1/1/2012', periods=1000, freq='S')\n",
    "ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)\n",
    "ts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 147,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00    76011\n",
       "2012-01-01 00:05:00    77349\n",
       "2012-01-01 00:10:00    73123\n",
       "2012-01-01 00:15:00    26538\n",
       "Freq: 5T, dtype: int32"
      ]
     },
     "execution_count": 147,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 每5分钟进行一次聚合\n",
    "ts.resample('5Min').sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "重采样功能非常灵活，您可以指定许多不同的参数来控制频率转换和重采样操作。\n",
    "\n",
    "通过分派可用的任何函数（类似于 grouby）都可以作为返回对象的方法，包括 sum，mean，std，sem，max，min，mid，median，first，last，ohlc："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 148,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00    253.370000\n",
       "2012-01-01 00:05:00    257.830000\n",
       "2012-01-01 00:10:00    243.743333\n",
       "2012-01-01 00:15:00    265.380000\n",
       "Freq: 5T, dtype: float64"
      ]
     },
     "execution_count": 148,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts.resample('5Min').mean() # 平均"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 149,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00    497\n",
       "2012-01-01 00:05:00    497\n",
       "2012-01-01 00:10:00    495\n",
       "2012-01-01 00:15:00    491\n",
       "Freq: 5T, dtype: int32"
      ]
     },
     "execution_count": 149,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts.resample('5Min').max() # 最大值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 美国线\n",
    "美国线（英语：Open-High-Low-Close chart，OHLC chart），以竖立的线条表现股票价格的变化，可以呈现“开盘价、最高价、最低价、收盘价”，竖线呈现最高价和最低价间的价差间距，左侧横线代表开盘价，右侧横线代表收盘价，绘制上较K线简单。另有一种美国线仅呈现“最高价、最低价、收盘价”（HLC）三项讯息。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 150,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>open</th>\n",
       "      <th>high</th>\n",
       "      <th>low</th>\n",
       "      <th>close</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:00:00</th>\n",
       "      <td>407</td>\n",
       "      <td>497</td>\n",
       "      <td>0</td>\n",
       "      <td>51</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:05:00</th>\n",
       "      <td>302</td>\n",
       "      <td>497</td>\n",
       "      <td>2</td>\n",
       "      <td>161</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:10:00</th>\n",
       "      <td>125</td>\n",
       "      <td>495</td>\n",
       "      <td>0</td>\n",
       "      <td>338</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:15:00</th>\n",
       "      <td>370</td>\n",
       "      <td>491</td>\n",
       "      <td>3</td>\n",
       "      <td>132</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                     open  high  low  close\n",
       "2012-01-01 00:00:00   407   497    0     51\n",
       "2012-01-01 00:05:00   302   497    2    161\n",
       "2012-01-01 00:10:00   125   495    0    338\n",
       "2012-01-01 00:15:00   370   491    3    132"
      ]
     },
     "execution_count": 150,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts.resample('5Min').ohlc()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 开闭区间指定\n",
    "对于采样，可以将 closed 设置为“ left”或“ right”，以指定关闭区间的哪一端："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 151,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2011-12-31 23:55:00    407.000000\n",
       "2012-01-01 00:00:00    253.020000\n",
       "2012-01-01 00:05:00    257.240000\n",
       "2012-01-01 00:10:00    244.560000\n",
       "2012-01-01 00:15:00    264.323232\n",
       "Freq: 5T, dtype: float64"
      ]
     },
     "execution_count": 151,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts.resample('5Min', closed='right').mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 152,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00    253.370000\n",
       "2012-01-01 00:05:00    257.830000\n",
       "2012-01-01 00:10:00    243.743333\n",
       "2012-01-01 00:15:00    265.380000\n",
       "Freq: 5T, dtype: float64"
      ]
     },
     "execution_count": 152,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts.resample('5Min', closed='left').mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 输出结果控制\n",
    "像 label 和 loffset 这样的参数用于操纵结果标签。 label 指定结果是用间隔的开始还是结束标记，loffset 对输出标签执行时间调整。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 153,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00    253.370000\n",
       "2012-01-01 00:05:00    257.830000\n",
       "2012-01-01 00:10:00    243.743333\n",
       "2012-01-01 00:15:00    265.380000\n",
       "Freq: 5T, dtype: float64"
      ]
     },
     "execution_count": 153,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts.resample('5Min').mean()  # 默认 label='left'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 154,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00    253.370000\n",
       "2012-01-01 00:05:00    257.830000\n",
       "2012-01-01 00:10:00    243.743333\n",
       "2012-01-01 00:15:00    265.380000\n",
       "Freq: 5T, dtype: float64"
      ]
     },
     "execution_count": 154,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts.resample('5Min', label='left').mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 上采样\n",
    "上采样又称图像插值，其主要目的是通过放大原图像，进而可以在更高分辨率的设备上显示。图像放大几乎都是采用内插值方法，即在原有图像像素的基础上在像素点之间采用合适的插值算法插入新的元素。\n",
    "\n",
    "对于上采样，您可以指定一种上采样的方法，并指定 limit 参数以对创建的间隙进行插值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 156,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00.000    407.0\n",
       "2012-01-01 00:00:00.250      NaN\n",
       "2012-01-01 00:00:00.500      NaN\n",
       "2012-01-01 00:00:00.750      NaN\n",
       "2012-01-01 00:00:01.000    176.0\n",
       "Freq: 250L, dtype: float64"
      ]
     },
     "execution_count": 156,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 从每秒到每250毫秒\n",
    "ts[:2].resample('250L').asfreq()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 157,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00.000    407\n",
       "2012-01-01 00:00:00.250    407\n",
       "2012-01-01 00:00:00.500    407\n",
       "2012-01-01 00:00:00.750    407\n",
       "2012-01-01 00:00:01.000    176\n",
       "Freq: 250L, dtype: int32"
      ]
     },
     "execution_count": 157,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts[:2].resample('250L').ffill()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 158,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00.000    407.0\n",
       "2012-01-01 00:00:00.250    407.0\n",
       "2012-01-01 00:00:00.500    407.0\n",
       "2012-01-01 00:00:00.750      NaN\n",
       "2012-01-01 00:00:01.000    176.0\n",
       "Freq: 250L, dtype: float64"
      ]
     },
     "execution_count": 158,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts[:2].resample('250L').ffill(limit=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 稀疏采样\n",
    "压缩感知（Compressed sensing），也被称为压缩采样（Compressive sampling）或稀疏采样（Sparse sampling），是一种寻找欠定线性系统的稀疏解的技术。压缩感知被应用于电子工程尤其是信号处理中，用于获取和重构稀疏或可压缩的信号。\n",
    "\n",
    "相对于要重采样的时间量，稀疏时间序列的点要少得多。 天真地对稀疏序列进行升采样可能会产生很多中间值。 当您不想使用一种方法来填充这些值时，例如 fill_method 为 None，则中间值将用 NaN 填充。由于重采样是基于时间的分组依据，因此以下是仅对并非全部为NaN的组进行有效重采样的方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 159,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2014-01-01 00:00:00     0\n",
       "2014-01-01 00:03:00     0\n",
       "2014-01-01 00:06:00     0\n",
       "2014-01-01 00:09:00     0\n",
       "2014-01-01 00:12:00     0\n",
       "                       ..\n",
       "2014-04-09 23:48:00     0\n",
       "2014-04-09 23:51:00     0\n",
       "2014-04-09 23:54:00     0\n",
       "2014-04-09 23:57:00     0\n",
       "2014-04-10 00:00:00    99\n",
       "Freq: 3T, Length: 47521, dtype: int64"
      ]
     },
     "execution_count": 159,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rng = pd.date_range('2014-1-1', periods=100, freq='D') + pd.Timedelta('1s')\n",
    "ts = pd.Series(range(100), index=rng)\n",
    "\n",
    "# 如果我们想对整个系列重新采样：\n",
    "ts.resample('3T').sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "取而代之的是，我们只能对那些我们拥有点的组重新采样，如下所示："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 160,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2014-01-01     0\n",
       "2014-01-02     1\n",
       "2014-01-03     2\n",
       "2014-01-04     3\n",
       "2014-01-05     4\n",
       "              ..\n",
       "2014-04-06    95\n",
       "2014-04-07    96\n",
       "2014-04-08    97\n",
       "2014-04-09    98\n",
       "2014-04-10    99\n",
       "Length: 100, dtype: int64"
      ]
     },
     "execution_count": 160,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from functools import partial\n",
    "from pandas.tseries.frequencies import to_offset\n",
    "\n",
    "def round(t, freq):\n",
    "    freq = to_offset(freq)\n",
    "    return pd.Timestamp((t.value // freq.delta.value) * freq.delta.value)\n",
    "\n",
    "ts.groupby(partial(round, freq='3T')).sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 聚合\n",
    "类似于 aggregating API, groupby API, 和窗口方法 api, Resampler 也适用相关方法。重新采样DataFrame时，默认值是对具有相同功能的所有列进行操作："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 161,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "      <th>C</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:00:00</th>\n",
       "      <td>-0.033312</td>\n",
       "      <td>0.048403</td>\n",
       "      <td>0.122693</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:03:00</th>\n",
       "      <td>0.057612</td>\n",
       "      <td>0.138748</td>\n",
       "      <td>-0.005933</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:06:00</th>\n",
       "      <td>-0.020865</td>\n",
       "      <td>0.039067</td>\n",
       "      <td>-0.023592</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:09:00</th>\n",
       "      <td>0.011191</td>\n",
       "      <td>-0.013045</td>\n",
       "      <td>0.030350</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:12:00</th>\n",
       "      <td>-0.136724</td>\n",
       "      <td>0.023454</td>\n",
       "      <td>-0.049614</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:15:00</th>\n",
       "      <td>0.032506</td>\n",
       "      <td>0.070861</td>\n",
       "      <td>0.124264</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                            A         B         C\n",
       "2012-01-01 00:00:00 -0.033312  0.048403  0.122693\n",
       "2012-01-01 00:03:00  0.057612  0.138748 -0.005933\n",
       "2012-01-01 00:06:00 -0.020865  0.039067 -0.023592\n",
       "2012-01-01 00:09:00  0.011191 -0.013045  0.030350\n",
       "2012-01-01 00:12:00 -0.136724  0.023454 -0.049614\n",
       "2012-01-01 00:15:00  0.032506  0.070861  0.124264"
      ]
     },
     "execution_count": 161,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.DataFrame(np.random.randn(1000, 3),\n",
    "                  index=pd.date_range('1/1/2012', freq='S', periods=1000),\n",
    "                  columns=['A', 'B', 'C'])\n",
    "\n",
    "r = df.resample('3T')\n",
    "r.mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们可以选择一个或多个特定列:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2012-01-01 00:00:00   -0.033312\n",
       "2012-01-01 00:03:00    0.057612\n",
       "2012-01-01 00:06:00   -0.020865\n",
       "2012-01-01 00:09:00    0.011191\n",
       "2012-01-01 00:12:00   -0.136724\n",
       "2012-01-01 00:15:00    0.032506\n",
       "Freq: 3T, Name: A, dtype: float64"
      ]
     },
     "execution_count": 162,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r['A'].mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:00:00</th>\n",
       "      <td>-0.033312</td>\n",
       "      <td>0.048403</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:03:00</th>\n",
       "      <td>0.057612</td>\n",
       "      <td>0.138748</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:06:00</th>\n",
       "      <td>-0.020865</td>\n",
       "      <td>0.039067</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:09:00</th>\n",
       "      <td>0.011191</td>\n",
       "      <td>-0.013045</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:12:00</th>\n",
       "      <td>-0.136724</td>\n",
       "      <td>0.023454</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:15:00</th>\n",
       "      <td>0.032506</td>\n",
       "      <td>0.070861</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                            A         B\n",
       "2012-01-01 00:00:00 -0.033312  0.048403\n",
       "2012-01-01 00:03:00  0.057612  0.138748\n",
       "2012-01-01 00:06:00 -0.020865  0.039067\n",
       "2012-01-01 00:09:00  0.011191 -0.013045\n",
       "2012-01-01 00:12:00 -0.136724  0.023454\n",
       "2012-01-01 00:15:00  0.032506  0.070861"
      ]
     },
     "execution_count": 163,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r[['A', 'B']].mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "多个聚合方式："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 164,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>sum</th>\n",
       "      <th>mean</th>\n",
       "      <th>std</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:00:00</th>\n",
       "      <td>-5.996128</td>\n",
       "      <td>-0.033312</td>\n",
       "      <td>0.937740</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:03:00</th>\n",
       "      <td>10.370077</td>\n",
       "      <td>0.057612</td>\n",
       "      <td>0.934882</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:06:00</th>\n",
       "      <td>-3.755667</td>\n",
       "      <td>-0.020865</td>\n",
       "      <td>0.953072</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:09:00</th>\n",
       "      <td>2.014386</td>\n",
       "      <td>0.011191</td>\n",
       "      <td>1.056193</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:12:00</th>\n",
       "      <td>-24.610344</td>\n",
       "      <td>-0.136724</td>\n",
       "      <td>0.976037</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:15:00</th>\n",
       "      <td>3.250625</td>\n",
       "      <td>0.032506</td>\n",
       "      <td>0.998992</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                           sum      mean       std\n",
       "2012-01-01 00:00:00  -5.996128 -0.033312  0.937740\n",
       "2012-01-01 00:03:00  10.370077  0.057612  0.934882\n",
       "2012-01-01 00:06:00  -3.755667 -0.020865  0.953072\n",
       "2012-01-01 00:09:00   2.014386  0.011191  1.056193\n",
       "2012-01-01 00:12:00 -24.610344 -0.136724  0.976037\n",
       "2012-01-01 00:15:00   3.250625  0.032506  0.998992"
      ]
     },
     "execution_count": 164,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r['A'].agg([np.sum, np.mean, np.std])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 165,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead tr th {\n",
       "        text-align: left;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <th colspan=\"2\" halign=\"left\">A</th>\n",
       "      <th colspan=\"2\" halign=\"left\">B</th>\n",
       "      <th colspan=\"2\" halign=\"left\">C</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <th>sum</th>\n",
       "      <th>mean</th>\n",
       "      <th>sum</th>\n",
       "      <th>mean</th>\n",
       "      <th>sum</th>\n",
       "      <th>mean</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:00:00</th>\n",
       "      <td>-5.996128</td>\n",
       "      <td>-0.033312</td>\n",
       "      <td>8.712526</td>\n",
       "      <td>0.048403</td>\n",
       "      <td>22.084827</td>\n",
       "      <td>0.122693</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:03:00</th>\n",
       "      <td>10.370077</td>\n",
       "      <td>0.057612</td>\n",
       "      <td>24.974586</td>\n",
       "      <td>0.138748</td>\n",
       "      <td>-1.067948</td>\n",
       "      <td>-0.005933</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:06:00</th>\n",
       "      <td>-3.755667</td>\n",
       "      <td>-0.020865</td>\n",
       "      <td>7.032081</td>\n",
       "      <td>0.039067</td>\n",
       "      <td>-4.246644</td>\n",
       "      <td>-0.023592</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:09:00</th>\n",
       "      <td>2.014386</td>\n",
       "      <td>0.011191</td>\n",
       "      <td>-2.348185</td>\n",
       "      <td>-0.013045</td>\n",
       "      <td>5.463043</td>\n",
       "      <td>0.030350</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:12:00</th>\n",
       "      <td>-24.610344</td>\n",
       "      <td>-0.136724</td>\n",
       "      <td>4.221691</td>\n",
       "      <td>0.023454</td>\n",
       "      <td>-8.930492</td>\n",
       "      <td>-0.049614</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:15:00</th>\n",
       "      <td>3.250625</td>\n",
       "      <td>0.032506</td>\n",
       "      <td>7.086119</td>\n",
       "      <td>0.070861</td>\n",
       "      <td>12.426425</td>\n",
       "      <td>0.124264</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                             A                    B                    C  \\\n",
       "                           sum      mean        sum      mean        sum   \n",
       "2012-01-01 00:00:00  -5.996128 -0.033312   8.712526  0.048403  22.084827   \n",
       "2012-01-01 00:03:00  10.370077  0.057612  24.974586  0.138748  -1.067948   \n",
       "2012-01-01 00:06:00  -3.755667 -0.020865   7.032081  0.039067  -4.246644   \n",
       "2012-01-01 00:09:00   2.014386  0.011191  -2.348185 -0.013045   5.463043   \n",
       "2012-01-01 00:12:00 -24.610344 -0.136724   4.221691  0.023454  -8.930492   \n",
       "2012-01-01 00:15:00   3.250625  0.032506   7.086119  0.070861  12.426425   \n",
       "\n",
       "                               \n",
       "                         mean  \n",
       "2012-01-01 00:00:00  0.122693  \n",
       "2012-01-01 00:03:00 -0.005933  \n",
       "2012-01-01 00:06:00 -0.023592  \n",
       "2012-01-01 00:09:00  0.030350  \n",
       "2012-01-01 00:12:00 -0.049614  \n",
       "2012-01-01 00:15:00  0.124264  "
      ]
     },
     "execution_count": 165,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r.agg([np.sum, np.mean]) # 每个列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 166,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:00:00</th>\n",
       "      <td>-5.996128</td>\n",
       "      <td>0.935210</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:03:00</th>\n",
       "      <td>10.370077</td>\n",
       "      <td>0.968908</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:06:00</th>\n",
       "      <td>-3.755667</td>\n",
       "      <td>0.983241</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:09:00</th>\n",
       "      <td>2.014386</td>\n",
       "      <td>0.982057</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:12:00</th>\n",
       "      <td>-24.610344</td>\n",
       "      <td>1.047875</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:15:00</th>\n",
       "      <td>3.250625</td>\n",
       "      <td>1.013443</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                             A         B\n",
       "2012-01-01 00:00:00  -5.996128  0.935210\n",
       "2012-01-01 00:03:00  10.370077  0.968908\n",
       "2012-01-01 00:06:00  -3.755667  0.983241\n",
       "2012-01-01 00:09:00   2.014386  0.982057\n",
       "2012-01-01 00:12:00 -24.610344  1.047875\n",
       "2012-01-01 00:15:00   3.250625  1.013443"
      ]
     },
     "execution_count": 166,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 不同的聚合方式\n",
    "r.agg({'A': np.sum,\n",
    "       'B': lambda x: np.std(x, ddof=1)})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 167,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:00:00</th>\n",
       "      <td>-5.996128</td>\n",
       "      <td>0.935210</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:03:00</th>\n",
       "      <td>10.370077</td>\n",
       "      <td>0.968908</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:06:00</th>\n",
       "      <td>-3.755667</td>\n",
       "      <td>0.983241</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:09:00</th>\n",
       "      <td>2.014386</td>\n",
       "      <td>0.982057</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:12:00</th>\n",
       "      <td>-24.610344</td>\n",
       "      <td>1.047875</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:15:00</th>\n",
       "      <td>3.250625</td>\n",
       "      <td>1.013443</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                             A         B\n",
       "2012-01-01 00:00:00  -5.996128  0.935210\n",
       "2012-01-01 00:03:00  10.370077  0.968908\n",
       "2012-01-01 00:06:00  -3.755667  0.983241\n",
       "2012-01-01 00:09:00   2.014386  0.982057\n",
       "2012-01-01 00:12:00 -24.610344  1.047875\n",
       "2012-01-01 00:15:00   3.250625  1.013443"
      ]
     },
     "execution_count": 167,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 用字符指定\n",
    "r.agg({'A': 'sum', 'B': 'std'})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 168,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead tr th {\n",
       "        text-align: left;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <th colspan=\"2\" halign=\"left\">A</th>\n",
       "      <th colspan=\"2\" halign=\"left\">B</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th></th>\n",
       "      <th>sum</th>\n",
       "      <th>std</th>\n",
       "      <th>mean</th>\n",
       "      <th>std</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:00:00</th>\n",
       "      <td>-5.996128</td>\n",
       "      <td>0.937740</td>\n",
       "      <td>0.048403</td>\n",
       "      <td>0.935210</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:03:00</th>\n",
       "      <td>10.370077</td>\n",
       "      <td>0.934882</td>\n",
       "      <td>0.138748</td>\n",
       "      <td>0.968908</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:06:00</th>\n",
       "      <td>-3.755667</td>\n",
       "      <td>0.953072</td>\n",
       "      <td>0.039067</td>\n",
       "      <td>0.983241</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:09:00</th>\n",
       "      <td>2.014386</td>\n",
       "      <td>1.056193</td>\n",
       "      <td>-0.013045</td>\n",
       "      <td>0.982057</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:12:00</th>\n",
       "      <td>-24.610344</td>\n",
       "      <td>0.976037</td>\n",
       "      <td>0.023454</td>\n",
       "      <td>1.047875</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2012-01-01 00:15:00</th>\n",
       "      <td>3.250625</td>\n",
       "      <td>0.998992</td>\n",
       "      <td>0.070861</td>\n",
       "      <td>1.013443</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                             A                   B          \n",
       "                           sum       std      mean       std\n",
       "2012-01-01 00:00:00  -5.996128  0.937740  0.048403  0.935210\n",
       "2012-01-01 00:03:00  10.370077  0.934882  0.138748  0.968908\n",
       "2012-01-01 00:06:00  -3.755667  0.953072  0.039067  0.983241\n",
       "2012-01-01 00:09:00   2.014386  1.056193 -0.013045  0.982057\n",
       "2012-01-01 00:12:00 -24.610344  0.976037  0.023454  1.047875\n",
       "2012-01-01 00:15:00   3.250625  0.998992  0.070861  1.013443"
      ]
     },
     "execution_count": 168,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r.agg({'A': ['sum', 'std'], 'B': ['mean', 'std']})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "迭代采样对象："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 171,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Group:  2017-01-01 00:00:00\n",
      "---------------------------\n",
      "2017-01-01 00:00:00    0\n",
      "2017-01-01 00:30:00    1\n",
      "2017-01-01 00:31:00    2\n",
      "dtype: int64\n",
      "\n",
      "Group:  2017-01-01 01:00:00\n",
      "---------------------------\n",
      "2017-01-01 01:00:00    3\n",
      "dtype: int64\n",
      "\n",
      "Group:  2017-01-01 02:00:00\n",
      "---------------------------\n",
      "Series([], dtype: int64)\n",
      "\n",
      "Group:  2017-01-01 03:00:00\n",
      "---------------------------\n",
      "2017-01-01 03:00:00    4\n",
      "2017-01-01 03:05:00    5\n",
      "dtype: int64\n",
      "\n"
     ]
    }
   ],
   "source": [
    "small = pd.Series(range(6),\n",
    "                  index=pd.to_datetime(['2017-01-01T00:00:00',\n",
    "                                        '2017-01-01T00:30:00',\n",
    "                                        '2017-01-01T00:31:00',\n",
    "                                        '2017-01-01T01:00:00',\n",
    "                                        '2017-01-01T03:00:00',\n",
    "                                        '2017-01-01T03:05:00'])\n",
    "                 )\n",
    "\n",
    "resampled = small.resample('H')\n",
    "\n",
    "for name, group in resampled:\n",
    "    print(\"Group: \", name)\n",
    "    print(\"-\" * 27)\n",
    "    print(group, end=\"\\n\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第六部分：时间窗口\n",
    "Pandas 窗口函数，为了处理数字数据，Pandas 提供几种窗口函数，如移动窗口函数(rolling())，扩展窗口函数(expanding())，指数加权滑动(ewm())，同时可在基基础上调用适合的统计函数，如求和、中位数、均值、协方差、方差、相关性等。\n",
    "\n",
    "**理解窗口**\n",
    "\n",
    "可以把“窗口”（windows）这个理解一个集合，一个窗口就是一个集合，在统计分析中有需要不同的「窗口」，比如一个部门分成不同组，在统计时会按组进行平均、排名等操作。再比如，在一些像时间这种有顺序的数据，我们可能5天分一组、一月分一组再进行排序、求中位数等计算。\n",
    "\n",
    "rolling(10) 与 groupby 很像，但并没有进行分组，而是创建了一个按移动 10（天）位的滑动窗口对象。我们再对每个对象进行统计操作。\n",
    "\n",
    "expanding，「扩展」从数据（大多情况下是时间）的起始处开始窗口，增加窗口直到指定的大小。\n",
    "\n",
    "以下是 Expanding vs. rolling window 图示：\n",
    "\n",
    "> ![pandas window](https://zhangyafei-1258643511.cos.ap-nanjing.myqcloud.com/Python/blog/pandas-expanding-rolling.jpg)\n",
    "\n",
    "以下是 rolling 动图示例：\n",
    "\n",
    "> ![pandas rolling](https://zhangyafei-1258643511.cos.ap-nanjing.myqcloud.com/Python/blog/pandas-rolling-demo.gif)\n",
    "\n",
    "以下是 expanding 动图示例：\n",
    "\n",
    "> ![pandas expanding](https://zhangyafei-1258643511.cos.ap-nanjing.myqcloud.com/Python/blog/pandas-expanding-demo.gif)\n",
    "\n",
    "**指数加权函数**\n",
    "\n",
    "指数加权函数（Exponential weighted moving），在上述两个统计方法中分组中的所有数值的权重都是一样的，指数加权就是我们对分组中的数据给予不同的权重用于后边的计算中。如指数移动平均（Exponential Moving Average）也叫权重移动平均（Weighted Moving Average），是以指数式递减加权的移动平均，各数值的加权影响力随时间呈指数式递减，时间越靠近当前时刻的数据加权影响力越大。\n",
    "\n",
    "梯度下降法，就是计算了梯度的指数加权平均数，并以此来更新权重，它的运行速度几乎总是快于标准的梯度下降算法。\n",
    "\n",
    "**Pandas 中的窗口**\n",
    "\n",
    "滚动对象通过.rolling调用返回：pandas.DataFrame.rolling()，pandas.Series.rolling() 等。扩展对象通过.expanding 调用返回：pandas.DataFrame.expanding()，pandas.Series.expanding() 等。EWM 对象由.ewm调用返回：pandas.DataFrame.ewm()，pandas.Series.ewm() 等。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 窗口函数 rolling\n",
    ".rolling()函数又叫移动窗口函数，此函数可以应用于一系列数据，指定参数window=n，并在其上调用适合的统计函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 创建 Rolling 对象\n",
    "创建 Rolling 对象后，可以对对象进行计算操作。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 173,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Rolling [window=60,center=False,axis=0]"
      ]
     },
     "execution_count": 173,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = pd.Series(np.random.randn(1000),\n",
    "              index=pd.date_range('1/1/2000', periods=1000))\n",
    "\n",
    "s = s.cumsum()\n",
    "r = s.rolling(window=60)\n",
    "r"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 参数\n",
    "\n",
    "在`.rolling()` 创建对象时，它支持以下参数：\n",
    "\n",
    "| 参数        | 说明                                                         |\n",
    "| ----------- | ------------------------------------------------------------ |\n",
    "| window      | 可选参数，表示时间窗的大小，注意有两种形式(int 或 offset)。如果使用 int，则数值表示计算统计量的观测值的数量即向前几个数据，如果是offset类型，表示时间窗的大小。 |\n",
    "| min_periods | 每个窗口最少包含的观测值数量，小于这个值的窗口结果为NaN，值可以是int，默认None，offset情况下，默认为1。 |\n",
    "| center      | 把窗口的标签设置为居中。布尔型，默认False，居右              |\n",
    "| win_type    | 窗口的类型，截取窗的各种函数，字符串类型，默认为None。       |\n",
    "| on          | 可选参数，对于dataframe而言，指定要计算滚动窗口的列，值为列名。 |\n",
    "| axis        | int、字符串，默认为0，即对列进行计算                         |\n",
    "| closed      | 定义区间的开闭，支持int类型的window。对于offset类型默认是左开右闭，默认为right，可以根据情况指定为left、both等。 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "窗口的类型 win_type\n",
    "将win_type 传递给.rolling 会生成一个通用的滚动窗口计算，该计算将根据 win_type进行加权。\n",
    "\n",
    "win_type 参数支持以下类型：\n",
    "\n",
    "- boxcar\n",
    "- triang\n",
    "- blackman\n",
    "- hamming\n",
    "- bartlett\n",
    "- parzen\n",
    "- bohman\n",
    "- blackmanharris\n",
    "- nuttall\n",
    "- barthann\n",
    "- kaiser (needs beta)\n",
    "- gaussian (needs std)\n",
    "- general_gaussian (needs power, width)\n",
    "- slepian (needs width)\n",
    "- exponential (needs tau)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 176,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2000-01-01          NaN\n",
       "2000-01-02          NaN\n",
       "2000-01-03          NaN\n",
       "2000-01-04          NaN\n",
       "2000-01-05    -0.421702\n",
       "                ...    \n",
       "2002-09-22    16.374412\n",
       "2002-09-23    16.199573\n",
       "2002-09-24    16.354381\n",
       "2002-09-25    16.715682\n",
       "2002-09-26    16.921977\n",
       "Freq: D, Length: 1000, dtype: float64"
      ]
     },
     "execution_count": 176,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.rolling(window=5, win_type='triang').mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 177,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2000-01-01          NaN\n",
       "2000-01-02          NaN\n",
       "2000-01-03          NaN\n",
       "2000-01-04          NaN\n",
       "2000-01-05    -0.043657\n",
       "                ...    \n",
       "2002-09-22    16.919401\n",
       "2002-09-23    15.615150\n",
       "2002-09-24    15.611811\n",
       "2002-09-25    17.326237\n",
       "2002-09-26    17.551819\n",
       "Freq: D, Length: 1000, dtype: float64"
      ]
     },
     "execution_count": 177,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.rolling(window=5, win_type='gaussian').mean(std=0.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 179,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2000-01-01          NaN\n",
       "2000-01-02          NaN\n",
       "2000-01-03          NaN\n",
       "2000-01-04          NaN\n",
       "2000-01-05    -0.444738\n",
       "                ...    \n",
       "2002-09-22    16.270742\n",
       "2002-09-23    16.406929\n",
       "2002-09-24    16.604883\n",
       "2002-09-25    16.525007\n",
       "2002-09-26    16.669580\n",
       "Freq: D, Length: 1000, dtype: float64"
      ]
     },
     "execution_count": 179,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 以下相同\n",
    "s.rolling(window=5, win_type='boxcar').mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 180,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2000-01-01          NaN\n",
       "2000-01-02          NaN\n",
       "2000-01-03          NaN\n",
       "2000-01-04          NaN\n",
       "2000-01-05    -0.444738\n",
       "                ...    \n",
       "2002-09-22    16.270742\n",
       "2002-09-23    16.406929\n",
       "2002-09-24    16.604883\n",
       "2002-09-25    16.525007\n",
       "2002-09-26    16.669580\n",
       "Freq: D, Length: 1000, dtype: float64"
      ]
     },
     "execution_count": 180,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.rolling(window=5).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 统计\n",
    "我们可以使用上边的统计方法对窗口进行计算："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 181,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2000-01-01          NaN\n",
       "2000-01-02          NaN\n",
       "2000-01-03          NaN\n",
       "2000-01-04          NaN\n",
       "2000-01-05          NaN\n",
       "                ...    \n",
       "2002-09-22    21.061487\n",
       "2002-09-23    20.917474\n",
       "2002-09-24    20.800376\n",
       "2002-09-25    20.661929\n",
       "2002-09-26    20.528112\n",
       "Freq: D, Length: 1000, dtype: float64"
      ]
     },
     "execution_count": 181,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r.mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 182,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<AxesSubplot:>"
      ]
     },
     "execution_count": 182,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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GZRSXLx4kenTp5vrpk6dysyZM1mwYIH5IWDp3LlzVKtWjRYtWvDSSy8ByTdFDx48CCS3iTdp0sSs5QMMGzbMKveMn5+fVbdIe2dyunPnDgCVK1fOcLs1a9YwZcoUu455Nzp27MikSZPo06cPp06domzZsrRv397Ms56Z+Ph4XnvtNXbs2MH06dN5++23uXnzJrdv3/bYKfWMWaB8fX3TPNeoUSP+/PNP8/rkKLaGwrrjR9Ia5B3PPfecOXx8y5YtTjvPd999pw8cOJBmfffu3TWgf/31V71o0SKrNAQDBw40l2vVqqV9fX11VFSUjomJ0YMGDdIhISF67ty5Vvuk/jl+/LjWWuuVK1daPc7MlClTNKBv3LiR4XajRo3SJUqUyPobYifL12L5/qxatSrD/bp27aoHDhyoz549m+Y9ef7553XJkiWdWu67FRMTo8uWLatr1KihIyMj0zz/2WefaUCfP3/e9YWzAxmkNZCavHC5W7dusWDBArMJxZkjN0eNGmXVlg7w559/smnTJgCOHj1K+/btrZ6/evWquRwYGMjgwYPx8/PD19eXL7/8En9/f6t9tm7dmua8RkIrY7SqvQmumjZtytNPP51p04avr2+G6W/79euXreYcy28hly9fBqBVq1bcf//9Ge73888/8/XXX5tpGSx9++23REREpBkR7A6FCxdm+PDhQPK3p127dnHlyhXmz59P8eLF02xfrVo1wLl/q84iQV64nDGZtdH+7azRhElJSYSFhaXpz2455d4PP/xA7dq1zeacunXropSifv365jaLFy9Oc+wGDRpw8eJFkpKS2LNnD02aNAGSe9/s2bPH7PK4b98+hgwZYvZtz0yvXr34+uuvrfppp8fX15eEhIR0bxRC8khbyxG5ixYt4pVXXrGrDEa5jSC4Z88etNbs27fP6l5GRn744QfAOs+O8eHZrVs3u8vhDImJicTHx5vXddCgQea9kBYtWqS7jxHk//77b9cU0oEkyAuXM7oTjhw5kooVK1oFXUeKjY1Fa22VigAwa2pDhw5lxIgRAEyYMAFI/uDRWlOkSBGzK51Rk02tYsWKKKWYOXMmjRs3ZtOmTfTv39+qn/WOHTtISkpy+E1So93YVm3eyLVi3FRevnw5s2fPtvv4TZo0MXPuKKUAGDNmDO3bt+fGjRs29zM+BIwAevnyZT766COrbSpVqmR3OZzBuAdkpJs4dOgQZcqUYdq0aWn+VgyVK1dmyZIldOjQwVXFdBxb7Tju+JE2+bxh8eLFLmnfvHDhggb04sWLrdbHxcVpQA8fPlzv2LHDqt24efPmunHjxrp9+/Y6IiLCrrZ0QJcqVUrfvn073eeKFCnisNdk+Pzzz7WXl5e+cOFCuimHjXsGYWFhWmutJ06cqL28vOxKTxwVFaU/++wzrZQy35eSJUumud9gKTo6WicmJmqttW7Xrp3Ve7px40b9448/6o4dO2pAly9f3q1pknfv3m3eC7p48aIG9KxZs9xWHkdA2uSFJ+nRowcbN26kfPnyTj2PkfUxde3M6Nq4aNEiOnbsCGBmqTx06BAdOnRg0qRJlChRgvvuu8+uc127ds3mN5KMar53a8iQIRw+fJjKlSszevRoqx4r4eHhZsbKiIgItm7dyt69e0lKSrLqEWTLihUrGDFiBN98842ZdsJyXEF66RTGjx9PhQoViImJSXNdixcvzqOPPmp2QQ0JCXFpSgad6v5G7dq1WbFiBVWrVjWbDhs1apTpcYKCgti2bRsbN27kt99+c0pZncJW9HfHj9Tk85433nhDv/zyyw451p07d8zapNZax8fH6xMnTqTbW6J58+ZmTbNTp0762LFjVrXPNWvW2H3e+vXr69atW6f73P333687duyY5ddiD6OHEKl64xw+fFgDeu7cuTohIUF37drV3C40NDTT4w4YMEADOjg4WD/55JNpesmk7mFjbFO1alUNaG9vb+3r62t+Yztx4oTWWuv33nvPPMann37q2DcjA99//715na9evapv376tZ82apQH99ddfa0AfPHgw0+OMGDFClypVKtNJY9yBDGrybg/slj8S5HO/pKQkvW7dOr17926t9b8BhXSab+Lj483n0msKSe2hhx7K0j+fMePS448/nibIZzSLU3qv6c6dO3Zv7whhYWFW5R05cqT5nNFt89ChQ1rrfz/QSpcurf/+++9Mj12nTh392GOPaa21PnbsmPm+BgQEpNv8lfpDoFevXvqRRx4x398LFy5orbUODg7Wy5cvN7dbtmyZo96ODFmW7aefftK9evXSs2fP1qTMEjZ69Gh96dKlTI/zzjvvaEB36NBBV6hQwQUlt19GQV6aa4TLJCQk0KBBA3r37s37778PWN+ECw0NtdresivjH3/8kenxt2/f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SbcXjJE33jLbZOog/8wzz9CqVSv279/PrVu3nFRqIURuJzV5B5k5cybDhg0DYPny5SQmJpo9YlIzauaPPvooxYsXB0gzAcjWrVs5dOgQSikKFSrktHILIXI3CfIOEBgYyJEjR1i0aJHVeiPvTGpRUVHmcr9+/ShdujQlSpSw2sbX15fo6GiGDRvG5s2bHV9oIUSeIEHeAZ5++mmef/55jh49SpcuXcz1tmrylk04c+bMYd++fWlurPr6+hIcHMySJUs4efKkU8othMj9JMg7QMWKFQEoXry4mZ4AYMuWLSQmJqbZ/rPPPgOSu0MWKlSIGjVqpNnG19eXffv2AXkvp48QwnEkyDvAnTt3zGRio0ePNtdPnTrVzDVjOHLkCMWLF2fVqlXmQKf09OnTx1wuX7684wsthMgTJMg7wNWrV82bqe3atQMw0wLv3r2bcePGERwcDMCVK1eIioqicuXKadrhLb300kusX78eb29v6tWr5+RXIITIraQLpQNMmTLFzO1+5swZAC5dugQk95vfsWMHBQsW5N133yU8PBwAezJu9uzZU7pPCiGyRYK8Azz88MPmsjEI6ocffmDnzp3Exsby+eef4+PjAySnGIZ/B08JIYQzSXONHc6fP0+RIkX4888/0zx36dIlfv75ZzPh2D333ANA8+bNmT17NkuWLKFo0aJcvXoVgFOnTuHv729zhKsQQjiSBHk77Ny5k7i4OA4cOADAd999x/79+wH46aefePjhh83cNUbwtkw73KVLFypVqgRA69atGTFihCuLL4TIw6S5xg5GU0uLFi0AzNzvWmv+/PNPihQpQpUqVYDkbpEAP//8MwMGDABg9erVQPLgqGrVqjF06FBXFl8IkYdJTd4OERERQPJUfHfu3LF6bs+ePdSvX9+88fr4448zevRo3nvvvTTH+fzzz5k/f75VzhohhHAmqcnbwWiKWblyJQ888AAAc+fO5ffff+fIkSOMHTvW3Nbb25vZs2db7T9x4kSmT5+On58fMTExZm1fCCGcTaKNHerXrw/AtGnTzHXlypXjxIkTQOY55G/evAlAdHQ0RYoUMWv9QgjhbBJt7NCvXz9z2ej6+N577zFgwAAiIyOpWrVqhvsXK1bMXC5SpIhzCimEEOmQmnwmbty4wdWrVylRogQ3b96kfv36hIWFcezYMeLi4sxUwRkZPXo0pUuX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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "s.plot(style='k--') # 绘图看一下变化，原数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 183,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<AxesSubplot:>"
      ]
     },
     "execution_count": 183,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "r.mean().plot(style='k')  # 绘图看一下变化，计算后的"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### DataFrame 的应用\n",
    "它们也可以应用于DataFrame对象。 这实际上只是将移动窗口运算符应用于DataFrame 的所有列的语法糖："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 184,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([<AxesSubplot:>, <AxesSubplot:>, <AxesSubplot:>, <AxesSubplot:>],\n",
       "      dtype=object)"
      ]
     },
     "execution_count": 184,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 4 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "df = pd.DataFrame(np.random.randn(1000, 4),\n",
    "                  index=pd.date_range('1/1/2000', periods=1000),\n",
    "                  columns=['A', 'B', 'C', 'D'])\n",
    "\n",
    "df = df.cumsum()\n",
    "# 操作并绘图\n",
    "df.rolling(window=60).sum().plot(subplots=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 统计方法\n",
    "\n",
    "提供许多常见的统计功能：\n",
    "\n",
    "| Method     | Description                                |\n",
    "| ---------- | ------------------------------------------ |\n",
    "| count()    | Number of non-null observations            |\n",
    "| sum()      | Sum of values                              |\n",
    "| mean()     | Mean of values                             |\n",
    "| median()   | Arithmetic median of values                |\n",
    "| min()      | Minimum                                    |\n",
    "| max()      | Maximum                                    |\n",
    "| std()      | Bessel-corrected sample standard deviation |\n",
    "| var()      | Unbiased variance                          |\n",
    "| skew()     | Sample skewness (3rd moment)               |\n",
    "| kurt()     | Sample kurtosis (4th moment)               |\n",
    "| quantile() | Sample quantile (value at %)               |\n",
    "| apply()    | Generic apply                              |\n",
    "| cov()      | Unbiased covariance (binary)               |\n",
    "| corr()     | Correlation (binary)                       |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用函数 apply()\n",
    "\n",
    "apply() 函数接受一个额外的 func 参数，并执行通用滚动计算。 func 参数应该是一个从 ndarray 输入生成单个值的函数。 假设我们要滚动计算平均绝对偏差："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 185,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<AxesSubplot:>"
      ]
     },
     "execution_count": 185,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def mad(x):\n",
    "    return np.fabs(x - x.mean()).mean()\n",
    "\n",
    "s.rolling(window=60).apply(mad, raw=True).plot(style='k')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 时间类型移动窗口\n",
    "可以将偏移量（或可转换）传递给.rolling() 方法，并使其根据传递的时间窗口生成可变大小的窗口。 对于每个时间点，这包括在指示的时间增量内出现的所有先前值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 186,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>B</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:00</th>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:01</th>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:02</th>\n",
       "      <td>2.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:03</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:04</th>\n",
       "      <td>4.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                       B\n",
       "2013-01-01 09:00:00  0.0\n",
       "2013-01-01 09:00:01  1.0\n",
       "2013-01-01 09:00:02  2.0\n",
       "2013-01-01 09:00:03  NaN\n",
       "2013-01-01 09:00:04  4.0"
      ]
     },
     "execution_count": 186,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dft = pd.DataFrame({'B': [0, 1, 2, np.nan, 4]},\n",
    "                   index=pd.date_range('20130101 09:00:00',\n",
    "                                       periods=5,\n",
    "                                       freq='s'))\n",
    "\n",
    "dft"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 187,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>B</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:00</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:01</th>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:02</th>\n",
       "      <td>3.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:03</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:04</th>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                       B\n",
       "2013-01-01 09:00:00  NaN\n",
       "2013-01-01 09:00:01  1.0\n",
       "2013-01-01 09:00:02  3.0\n",
       "2013-01-01 09:00:03  NaN\n",
       "2013-01-01 09:00:04  NaN"
      ]
     },
     "execution_count": 187,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dft.rolling(2).sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 188,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>B</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:00</th>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:01</th>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:02</th>\n",
       "      <td>3.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:03</th>\n",
       "      <td>2.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:04</th>\n",
       "      <td>4.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                       B\n",
       "2013-01-01 09:00:00  0.0\n",
       "2013-01-01 09:00:01  1.0\n",
       "2013-01-01 09:00:02  3.0\n",
       "2013-01-01 09:00:03  2.0\n",
       "2013-01-01 09:00:04  4.0"
      ]
     },
     "execution_count": 188,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dft.rolling(2, min_periods=1).sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "指定移动频率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 189,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>B</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:00</th>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:01</th>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:02</th>\n",
       "      <td>3.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:03</th>\n",
       "      <td>2.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2013-01-01 09:00:04</th>\n",
       "      <td>4.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                       B\n",
       "2013-01-01 09:00:00  0.0\n",
       "2013-01-01 09:00:01  1.0\n",
       "2013-01-01 09:00:02  3.0\n",
       "2013-01-01 09:00:03  2.0\n",
       "2013-01-01 09:00:04  4.0"
      ]
     },
     "execution_count": 189,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dft.rolling('2s').sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**时间感知滚动与重采样**  \n",
    "将 .rolling() 与基于时间的索引一起使用非常类似于重采样。它们既对时间索引的 Pandas 对象进行操作又执行还原操作。\n",
    "\n",
    "当使用带有偏移量的.rolling() 时。偏移量是时间增量。取得一个向后看的窗口，并汇总该窗口中的所有值（包括终点，但不包括起点）。这是结果中此时的新值。对于输入的每个点，这些都是时空可变大小的窗口，将获得与输入相同大小的结果。\n",
    "\n",
    "当使用带有偏移量的.resample() 时。构造一个新的索引，它是偏移的频率。对于每个频率仓，在该时间仓中的时间倒退窗口内，从输入汇总点。聚合的结果是该频率点的输出。窗口在频率空间中是固定大小的。您的结果将具有介于原始输入对象的最小值和最大值之间的规则频率形状。\n",
    "\n",
    "总而言之，.rolling() 是基于时间的窗口操作，而.resample() 是基于频率的窗口操作。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 扩展窗口函数 expanding\n",
    "滚动统计的一种常见替代方法是使用扩展窗口，该窗口可生成该统计的值以及该时间点之前所有可用的数据。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用\n",
    "它们遵循与.rolling 类似的接口，其中.expanding 方法返回 Expanding 对象。\n",
    "\n",
    "由于这些计算是滚动统计的特殊情况，因此它们在 Pandas 中实现，因此以下两个调用是等效的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 197,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "      <th>C</th>\n",
       "      <th>D</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2000-01-01</th>\n",
       "      <td>1.049313</td>\n",
       "      <td>0.111910</td>\n",
       "      <td>0.322994</td>\n",
       "      <td>-1.091590</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2000-01-02</th>\n",
       "      <td>0.919457</td>\n",
       "      <td>-0.534175</td>\n",
       "      <td>0.146955</td>\n",
       "      <td>-1.443932</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2000-01-03</th>\n",
       "      <td>0.876989</td>\n",
       "      <td>-0.459435</td>\n",
       "      <td>0.209525</td>\n",
       "      <td>-1.924145</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2000-01-04</th>\n",
       "      <td>0.963262</td>\n",
       "      <td>-0.896879</td>\n",
       "      <td>0.056904</td>\n",
       "      <td>-2.227882</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2000-01-05</th>\n",
       "      <td>0.960253</td>\n",
       "      <td>-0.964472</td>\n",
       "      <td>0.224515</td>\n",
       "      <td>-2.138985</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                   A         B         C         D\n",
       "2000-01-01  1.049313  0.111910  0.322994 -1.091590\n",
       "2000-01-02  0.919457 -0.534175  0.146955 -1.443932\n",
       "2000-01-03  0.876989 -0.459435  0.209525 -1.924145\n",
       "2000-01-04  0.963262 -0.896879  0.056904 -2.227882\n",
       "2000-01-05  0.960253 -0.964472  0.224515 -2.138985"
      ]
     },
     "execution_count": 197,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.rolling(window=len(df), min_periods=1).mean()[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 198,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>A</th>\n",
       "      <th>B</th>\n",
       "      <th>C</th>\n",
       "      <th>D</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2000-01-01</th>\n",
       "      <td>1.049313</td>\n",
       "      <td>0.111910</td>\n",
       "      <td>0.322994</td>\n",
       "      <td>-1.091590</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2000-01-02</th>\n",
       "      <td>0.919457</td>\n",
       "      <td>-0.534175</td>\n",
       "      <td>0.146955</td>\n",
       "      <td>-1.443932</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2000-01-03</th>\n",
       "      <td>0.876989</td>\n",
       "      <td>-0.459435</td>\n",
       "      <td>0.209525</td>\n",
       "      <td>-1.924145</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2000-01-04</th>\n",
       "      <td>0.963262</td>\n",
       "      <td>-0.896879</td>\n",
       "      <td>0.056904</td>\n",
       "      <td>-2.227882</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2000-01-05</th>\n",
       "      <td>0.960253</td>\n",
       "      <td>-0.964472</td>\n",
       "      <td>0.224515</td>\n",
       "      <td>-2.138985</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                   A         B         C         D\n",
       "2000-01-01  1.049313  0.111910  0.322994 -1.091590\n",
       "2000-01-02  0.919457 -0.534175  0.146955 -1.443932\n",
       "2000-01-03  0.876989 -0.459435  0.209525 -1.924145\n",
       "2000-01-04  0.963262 -0.896879  0.056904 -2.227882\n",
       "2000-01-05  0.960253 -0.964472  0.224515 -2.138985"
      ]
     },
     "execution_count": 198,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.expanding(min_periods=1).mean()[:5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 统计方法\n",
    "\n",
    "具有与.rolling方法类似的方法:\n",
    "\n",
    "| Method     | Description                                |\n",
    "| ---------- | ------------------------------------------ |\n",
    "| count()    | Number of non-null observations            |\n",
    "| sum()      | Sum of values                              |\n",
    "| mean()     | Mean of values                             |\n",
    "| median()   | Arithmetic median of values                |\n",
    "| min()      | Minimum                                    |\n",
    "| max()      | Maximum                                    |\n",
    "| std()      | Bessel-corrected sample standard deviation |\n",
    "| var()      | Unbiased variance                          |\n",
    "| skew()     | Sample skewness (3rd moment)               |\n",
    "| kurt()     | Sample kurtosis (4th moment)               |\n",
    "| quantile() | Sample quantile (value at %)               |\n",
    "| apply()    | Generic apply                              |\n",
    "| cov()      | Unbiased covariance (binary)               |\n",
    "| corr()     | Correlation (binary)                       |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 几个特别的Expanding类型函数\n",
    "cumsum/cumprod/cummax/cummin都是特殊expanding累计计算方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 203,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2000-01-01   -0.763718\n",
       "2000-01-02   -2.799295\n",
       "2000-01-03   -2.842953\n",
       "2000-01-04   -2.291686\n",
       "2000-01-05   -2.223691\n",
       "Freq: D, dtype: float64"
      ]
     },
     "execution_count": 203,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.cumsum().head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 204,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2000-01-01   -0.763718\n",
       "2000-01-02   -2.799295\n",
       "2000-01-03   -2.842953\n",
       "2000-01-04   -2.291686\n",
       "2000-01-05   -2.223691\n",
       "Freq: D, dtype: float64"
      ]
     },
     "execution_count": 204,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.cumsum().head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "shift/diff/pct_change都是涉及到了元素关系  \n",
    "①shift是指序列索引不变，但值向后移动  \n",
    "②diff是指前后元素的差，period参数表示间隔，默认为1，并且可以为负  \n",
    "③pct_change是值前后元素的变化百分比，period参数与diff类似  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 205,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2000-01-01         NaN\n",
       "2000-01-02         NaN\n",
       "2000-01-03   -0.763718\n",
       "2000-01-04   -2.035577\n",
       "2000-01-05   -0.043657\n",
       "Freq: D, dtype: float64"
      ]
     },
     "execution_count": 205,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.shift(2).head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 206,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2000-01-01         NaN\n",
       "2000-01-02         NaN\n",
       "2000-01-03         NaN\n",
       "2000-01-04    1.314986\n",
       "2000-01-05    2.103571\n",
       "Freq: D, dtype: float64"
      ]
     },
     "execution_count": 206,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.diff(3).head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 207,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2000-01-01         NaN\n",
       "2000-01-02         NaN\n",
       "2000-01-03         NaN\n",
       "2000-01-04   -1.721820\n",
       "2000-01-05   -1.033403\n",
       "Freq: D, dtype: float64"
      ]
     },
     "execution_count": 207,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.pct_change(3).head()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "272px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
